+}
+
+/* Transform section name S for a name comparison. prelink can split section
+ `.bss' into two sections `.dynbss' and `.bss' (in this order). Similarly
+ prelink can split `.sbss' into `.sdynbss' and `.sbss'. Use virtual address
+ of the new `.dynbss' (`.sdynbss') section as the adjacent new `.bss'
+ (`.sbss') section has invalid (increased) virtual address. */
+
+static const char *
+addr_section_name (const char *s)
+{
+ if (strcmp (s, ".dynbss") == 0)
+ return ".bss";
+ if (strcmp (s, ".sdynbss") == 0)
+ return ".sbss";
+
+ return s;
+}
+
+/* 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 (addr_section_name (a->name), addr_section_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. */
+
+void
+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. */
+ lower_sect = NULL;
+ bfd_map_over_sections (abfd, find_lowest_section, &lower_sect);
+ if (lower_sect == NULL)
+ {
+ warning (_("no loadable sections found in added symbol-file %s"),
+ bfd_get_filename (abfd));
+ lower_offset = 0;
+ }
+ 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 = addr_section_name ((*addrs_sorted)->name);
+
+ while (*abfd_addrs_sorted
+ && strcmp (addr_section_name ((*abfd_addrs_sorted)->name),
+ sect_name) < 0)
+ abfd_addrs_sorted++;
+
+ if (*abfd_addrs_sorted
+ && strcmp (addr_section_name ((*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!!!
+
+ Adjust offsets if the segments are not contiguous.
+ If the section is contiguous, its offset should be set to
+ the offset of the highest loadable section lower than it
+ (the loadable section directly below it in memory).
+ this_offset = lower_offset = lower_addr - lower_orig_addr */
+
+ for (i = 0; i < addrs->num_sections && addrs->other[i].name; i++)
+ {
+ struct other_sections *sect = addrs_to_abfd_addrs[i];
+
+ if (sect)
+ {
+ /* This is the index used by BFD. */
+ addrs->other[i].sectindex = sect->sectindex;
+
+ if (addrs->other[i].addr != 0)
+ {
+ addrs->other[i].addr -= sect->addr;
+ lower_offset = addrs->other[i].addr;
+ }
+ else
+ addrs->other[i].addr = lower_offset;
+ }
+ else
+ {
+ /* addr_section_name transformation is not used for SECT_NAME. */
+ const char *sect_name = addrs->other[i].name;
+
+ /* This section does not exist in ABFD, which is normally
+ unexpected and we want to issue a warning.
+
+ However, the ELF prelinker does create a few sections which are
+ marked in the main executable as loadable (they are loaded in
+ memory from the DYNAMIC segment) and yet are not present in
+ separate debug info files. This is fine, and should not cause
+ a warning. Shared libraries contain just the section
+ ".gnu.liblist" but it is not marked as loadable there. There is
+ no other way to identify them than by their name as the sections
+ created by prelink have no special flags.
+
+ For the sections `.bss' and `.sbss' see addr_section_name. */
+
+ if (!(strcmp (sect_name, ".gnu.liblist") == 0
+ || strcmp (sect_name, ".gnu.conflict") == 0
+ || (strcmp (sect_name, ".bss") == 0
+ && i > 0
+ && strcmp (addrs->other[i - 1].name, ".dynbss") == 0
+ && addrs_to_abfd_addrs[i - 1] != NULL)
+ || (strcmp (sect_name, ".sbss") == 0
+ && i > 0
+ && strcmp (addrs->other[i - 1].name, ".sdynbss") == 0
+ && addrs_to_abfd_addrs[i - 1] != NULL)))
+ warning (_("section %s not found in %s"), sect_name,
+ bfd_get_filename (abfd));
+
+ addrs->other[i].addr = 0;
+
+ /* 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
+ of how to represent it for fast symbol reading. This is the default
+ version of the sym_fns.sym_offsets function for symbol readers that
+ don't need to do anything special. It allocates a section_offsets table
+ for the objectfile OBJFILE and stuffs ADDR into all of the offsets. */
+
+void
+default_symfile_offsets (struct objfile *objfile,
+ struct section_addr_info *addrs)
+{
+ objfile->num_sections = bfd_count_sections (objfile->obfd);
+ objfile->section_offsets = (struct section_offsets *)
+ obstack_alloc (&objfile->objfile_obstack,
+ SIZEOF_N_SECTION_OFFSETS (objfile->num_sections));
+ relative_addr_info_to_section_offsets (objfile->section_offsets,
+ objfile->num_sections, addrs);