+struct symfile_segment_data *
+get_symfile_segment_data (bfd *abfd)
+{
+ struct sym_fns *sf = find_sym_fns (abfd);
+
+ if (sf == NULL)
+ return NULL;
+
+ return sf->sym_segments (abfd);
+}
+
+void
+free_symfile_segment_data (struct symfile_segment_data *data)
+{
+ xfree (data->segment_bases);
+ xfree (data->segment_sizes);
+ xfree (data->segment_info);
+ xfree (data);
+}
+
+
+/* Given:
+ - DATA, containing segment addresses from the object file ABFD, and
+ the mapping from ABFD's sections onto the segments that own them,
+ and
+ - SEGMENT_BASES[0 .. NUM_SEGMENT_BASES - 1], holding the actual
+ segment addresses reported by the target,
+ store the appropriate offsets for each section in OFFSETS.
+
+ If there are fewer entries in SEGMENT_BASES than there are segments
+ in DATA, then apply SEGMENT_BASES' last entry to all the segments.
+
+ If there are more, then verify that all the excess addresses are
+ the same as the last legitimate one, and then ignore them. This
+ allows "TextSeg=X;DataSeg=X" qOffset replies for files which have
+ only a single segment. */
+int
+symfile_map_offsets_to_segments (bfd *abfd, struct symfile_segment_data *data,
+ struct section_offsets *offsets,
+ int num_segment_bases,
+ const CORE_ADDR *segment_bases)
+{
+ int i;
+ asection *sect;
+
+ /* It doesn't make sense to call this function unless you have some
+ segment base addresses. */
+ gdb_assert (segment_bases > 0);
+
+ /* If we do not have segment mappings for the object file, we
+ can not relocate it by segments. */
+ gdb_assert (data != NULL);
+ gdb_assert (data->num_segments > 0);
+
+ /* Check any extra SEGMENT_BASES entries. */
+ if (num_segment_bases > data->num_segments)
+ for (i = data->num_segments; i < num_segment_bases; i++)
+ if (segment_bases[i] != segment_bases[data->num_segments - 1])
+ return 0;
+
+ for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+ {
+ int which = data->segment_info[i];
+
+ gdb_assert (0 <= which && which <= data->num_segments);
+
+ /* Don't bother computing offsets for sections that aren't
+ loaded as part of any segment. */
+ if (! which)
+ continue;
+
+ /* Use the last SEGMENT_BASES entry as the address of any extra
+ segments mentioned in DATA->segment_info. */
+ if (which > num_segment_bases)
+ which = num_segment_bases;
+
+ offsets->offsets[i] = (segment_bases[which - 1]
+ - data->segment_bases[which - 1]);
+ }
+
+ return 1;
+}
+
+static void
+symfile_find_segment_sections (struct objfile *objfile)
+{
+ bfd *abfd = objfile->obfd;
+ int i;
+ asection *sect;
+ struct symfile_segment_data *data;
+
+ data = get_symfile_segment_data (objfile->obfd);
+ if (data == NULL)
+ return;
+
+ if (data->num_segments != 1 && data->num_segments != 2)
+ {
+ free_symfile_segment_data (data);
+ return;
+ }
+
+ for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next)
+ {
+ CORE_ADDR vma;
+ int which = data->segment_info[i];
+
+ if (which == 1)
+ {
+ if (objfile->sect_index_text == -1)
+ objfile->sect_index_text = sect->index;
+
+ if (objfile->sect_index_rodata == -1)
+ objfile->sect_index_rodata = sect->index;
+ }
+ else if (which == 2)
+ {
+ if (objfile->sect_index_data == -1)
+ objfile->sect_index_data = sect->index;
+
+ if (objfile->sect_index_bss == -1)
+ objfile->sect_index_bss = sect->index;
+ }
+ }
+
+ free_symfile_segment_data (data);
+}
+