From 82ccf5a5777fc9fda05b4d107a476a69b66002dc Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Thu, 25 Mar 2010 20:29:30 +0000 Subject: [PATCH] gdb/ * symfile.c (build_section_addr_info_from_bfd): New. (build_section_addr_info_from_objfile): Base it on build_section_addr_info_from_bfd. (addrs_section_compar, addrs_section_sort): New. (addr_info_make_relative): New variables my_cleanup, abfd_addrs, addrs_sorted, abfd_addrs_sorted and addrs_to_abfd_addrs. Build addrs_to_abfd_addrs. Use it for recalculating ADDRS. gdb/testsuite/ * gdb.base/dup-sect.exp, gdb.base/dup-sect.S: New. --- gdb/ChangeLog | 10 ++ gdb/symfile.c | 139 +++++++++++++++++++++++++--- gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.base/dup-sect.S | 22 +++++ gdb/testsuite/gdb.base/dup-sect.exp | 79 ++++++++++++++++ 5 files changed, 241 insertions(+), 13 deletions(-) create mode 100644 gdb/testsuite/gdb.base/dup-sect.S create mode 100644 gdb/testsuite/gdb.base/dup-sect.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0d983ec42db..d3ecb9141f5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2010-03-25 Jan Kratochvil + + * symfile.c (build_section_addr_info_from_bfd): New. + (build_section_addr_info_from_objfile): Base it on + build_section_addr_info_from_bfd. + (addrs_section_compar, addrs_section_sort): New. + (addr_info_make_relative): New variables my_cleanup, abfd_addrs, + addrs_sorted, abfd_addrs_sorted and addrs_to_abfd_addrs. Build + addrs_to_abfd_addrs. Use it for recalculating ADDRS. + 2010-03-24 Michael Snyder * elfread.c (find_separate_debug_file_by_buildid): diff --git a/gdb/symfile.c b/gdb/symfile.c index c1d64eaa5c0..eda26cc0436 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -319,29 +319,47 @@ build_section_addr_info_from_section_table (const struct target_section *start, return sap; } -/* Create a section_addr_info from section offsets in OBJFILE. */ +/* Create a section_addr_info from section offsets in ABFD. */ -struct section_addr_info * -build_section_addr_info_from_objfile (const struct objfile *objfile) +static struct section_addr_info * +build_section_addr_info_from_bfd (bfd *abfd) { struct section_addr_info *sap; int i; struct bfd_section *sec; - sap = alloc_section_addr_info (objfile->num_sections); - for (i = 0, sec = objfile->obfd->sections; sec != NULL; sec = sec->next) - if (bfd_get_section_flags (objfile->obfd, sec) & (SEC_ALLOC | SEC_LOAD)) + sap = alloc_section_addr_info (bfd_count_sections (abfd)); + for (i = 0, sec = abfd->sections; sec != NULL; sec = sec->next) + if (bfd_get_section_flags (abfd, sec) & (SEC_ALLOC | SEC_LOAD)) { - sap->other[i].addr = (bfd_get_section_vma (objfile->obfd, sec) - + objfile->section_offsets->offsets[i]); - sap->other[i].name = xstrdup (bfd_get_section_name (objfile->obfd, - sec)); + sap->other[i].addr = bfd_get_section_vma (abfd, sec); + sap->other[i].name = xstrdup (bfd_get_section_name (abfd, sec)); sap->other[i].sectindex = sec->index; i++; } return sap; } +/* Create a section_addr_info from section offsets in OBJFILE. */ + +struct section_addr_info * +build_section_addr_info_from_objfile (const struct objfile *objfile) +{ + struct section_addr_info *sap; + int i; + + /* Before reread_symbols gets rewritten it is not safe to call: + gdb_assert (objfile->num_sections == bfd_count_sections (objfile->obfd)); + */ + sap = build_section_addr_info_from_bfd (objfile->obfd); + for (i = 0; i < sap->num_sections && sap->other[i].name; i++) + { + int sectindex = sap->other[i].sectindex; + + sap->other[i].addr += objfile->section_offsets->offsets[sectindex]; + } + return sap; +} /* Free all memory allocated by build_section_addr_info_from_section_table. */ @@ -519,6 +537,46 @@ relative_addr_info_to_section_offsets (struct section_offsets *section_offsets, } } +/* qsort comparator for addrs_section_sort. Sort entries in ascending order by + their (name, sectindex) pair. sectindex makes the sort by name stable. */ + +static int +addrs_section_compar (const void *ap, const void *bp) +{ + const struct other_sections *a = *((struct other_sections **) ap); + const struct other_sections *b = *((struct other_sections **) bp); + int retval, a_idx, b_idx; + + retval = strcmp (a->name, b->name); + if (retval) + return retval; + + /* SECTINDEX is undefined iff ADDR is zero. */ + a_idx = a->addr == 0 ? 0 : a->sectindex; + b_idx = b->addr == 0 ? 0 : b->sectindex; + return a_idx - b_idx; +} + +/* Provide sorted array of pointers to sections of ADDRS. The array is + terminated by NULL. Caller is responsible to call xfree for it. */ + +static struct other_sections ** +addrs_section_sort (struct section_addr_info *addrs) +{ + struct other_sections **array; + int i; + + /* `+ 1' for the NULL terminator. */ + array = xmalloc (sizeof (*array) * (addrs->num_sections + 1)); + for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++) + array[i] = &addrs->other[i]; + array[i] = NULL; + + qsort (array, i, sizeof (*array), addrs_section_compar); + + return array; +} + /* Relativize absolute addresses in ADDRS into offsets based on ABFD. Fill-in also SECTINDEXes specific to ABFD there. This function can be used to rebase ADDRS to start referencing different BFD than before. */ @@ -529,6 +587,10 @@ addr_info_make_relative (struct section_addr_info *addrs, bfd *abfd) asection *lower_sect; CORE_ADDR lower_offset; int i; + struct cleanup *my_cleanup; + struct section_addr_info *abfd_addrs; + struct other_sections **addrs_sorted, **abfd_addrs_sorted; + struct other_sections **addrs_to_abfd_addrs; /* Find lowest loadable section to be used as starting point for continguous sections. */ @@ -543,6 +605,55 @@ addr_info_make_relative (struct section_addr_info *addrs, bfd *abfd) else lower_offset = bfd_section_vma (bfd_get_filename (abfd), lower_sect); + /* Create ADDRS_TO_ABFD_ADDRS array to map the sections in ADDRS to sections + in ABFD. Section names are not unique - there can be multiple sections of + the same name. Also the sections of the same name do not have to be + adjacent to each other. Some sections may be present only in one of the + files. Even sections present in both files do not have to be in the same + order. + + Use stable sort by name for the sections in both files. Then linearly + scan both lists matching as most of the entries as possible. */ + + addrs_sorted = addrs_section_sort (addrs); + my_cleanup = make_cleanup (xfree, addrs_sorted); + + abfd_addrs = build_section_addr_info_from_bfd (abfd); + make_cleanup_free_section_addr_info (abfd_addrs); + abfd_addrs_sorted = addrs_section_sort (abfd_addrs); + make_cleanup (xfree, abfd_addrs_sorted); + + /* Now create ADDRS_TO_ABFD_ADDRS from ADDRS_SORTED and ABFD_ADDRS_SORTED. */ + + addrs_to_abfd_addrs = xzalloc (sizeof (*addrs_to_abfd_addrs) + * addrs->num_sections); + make_cleanup (xfree, addrs_to_abfd_addrs); + + while (*addrs_sorted) + { + const char *sect_name = (*addrs_sorted)->name; + + while (*abfd_addrs_sorted + && strcmp ((*abfd_addrs_sorted)->name, sect_name) < 0) + abfd_addrs_sorted++; + + if (*abfd_addrs_sorted + && strcmp ((*abfd_addrs_sorted)->name, sect_name) == 0) + { + int index_in_addrs; + + /* Make the found item directly addressable from ADDRS. */ + index_in_addrs = *addrs_sorted - addrs->other; + gdb_assert (addrs_to_abfd_addrs[index_in_addrs] == NULL); + addrs_to_abfd_addrs[index_in_addrs] = *abfd_addrs_sorted; + + /* Never use the same ABFD entry twice. */ + abfd_addrs_sorted++; + } + + addrs_sorted++; + } + /* Calculate offsets for the loadable sections. FIXME! Sections must be in order of increasing loadable section so that contiguous sections can use the lower-offset!!! @@ -556,16 +667,16 @@ addr_info_make_relative (struct section_addr_info *addrs, bfd *abfd) for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++) { const char *sect_name = addrs->other[i].name; - asection *sect = bfd_get_section_by_name (abfd, sect_name); + struct other_sections *sect = addrs_to_abfd_addrs[i]; if (sect) { /* This is the index used by BFD. */ - addrs->other[i].sectindex = sect->index; + addrs->other[i].sectindex = sect->sectindex; if (addrs->other[i].addr != 0) { - addrs->other[i].addr -= bfd_section_vma (abfd, sect); + addrs->other[i].addr -= sect->addr; lower_offset = addrs->other[i].addr; } else @@ -597,6 +708,8 @@ addr_info_make_relative (struct section_addr_info *addrs, bfd *abfd) /* SECTINDEX is invalid if ADDR is zero. */ } } + + do_cleanups (my_cleanup); } /* Parse the user's idea of an offset for dynamic linking, into our idea diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 78170b2c7f4..33652d13bdd 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2010-03-25 Jan Kratochvil + + * gdb.base/dup-sect.exp, gdb.base/dup-sect.S: New. + 2010-03-24 Daniel Jacobowitz * gdb.base/completion.exp: Allow long instead of long int. diff --git a/gdb/testsuite/gdb.base/dup-sect.S b/gdb/testsuite/gdb.base/dup-sect.S new file mode 100644 index 00000000000..69bdbed02fe --- /dev/null +++ b/gdb/testsuite/gdb.base/dup-sect.S @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + + .section sect1, "a" +var1: .byte 1 + + .section sect2, "a" +var2: .byte 2 diff --git a/gdb/testsuite/gdb.base/dup-sect.exp b/gdb/testsuite/gdb.base/dup-sect.exp new file mode 100644 index 00000000000..08ab1d04641 --- /dev/null +++ b/gdb/testsuite/gdb.base/dup-sect.exp @@ -0,0 +1,79 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test inappropriate offseting of multiple sections with the same name. +# When kept in object file (before final executable link) it still works. +# When separate debug info file is not used it still works. +# When the ELF symbol table is kept in the main binary it still works. +# Used .S file as in .c file we would need __attriute__((section)) which is +# a GCC extension. + +# This test can only be run on targets which support ELF and use gas. +# For now pick a sampling of likely targets. +if {![istarget *-*-linux*] + && ![istarget *-*-gnu*] + && ![istarget *-*-elf*] + && ![istarget arm-*-eabi*] + && ![istarget powerpc-*-eabi*]} { + return 0 +} + +set testfile dup-sect +set srcfile ${testfile}.S +set srcmainfile start.c +set executable ${testfile} +set binfile ${objdir}/${subdir}/${executable} + +if {[build_executable ${testfile}.exp $executable [list ${srcfile} ${srcmainfile}] {}] == -1} { + return -1 +} + +set test "rename section" +set objcopy_program [transform objcopy] +set result [catch "exec $objcopy_program --rename-section sect2=sect1 $binfile" output] +verbose "result is $result" +verbose "output is $output" +if {$result != 0} { + fail $test + return +} +pass $test + +set test "split" +if {[gdb_gnu_strip_debug $binfile] != 0} { + fail $test +} else { + pass $test +} + +# gdb_gnu_strip_debug uses only --strip-debug and keeps the ELF symbol table +# in $binfile. +set test "strip" +set strip_program [transform strip] +set result [catch "exec $strip_program $binfile" output] +verbose "result is $result" +verbose "output is $output" +if {$result != 0} { + fail $test + return +} +pass $test + +clean_restart $executable + +gdb_test "p/d *(const char *) &var1" " = 1" "var1 after strip" +gdb_test "p/d *(const char *) &var2" " = 2" "var2 after strip" -- 2.30.2