/* Definitions for targets which report shared library events.
- Copyright (C) 2007
- Free Software Foundation, Inc.
+ Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GDB.
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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "objfiles.h"
#include "symfile.h"
#include "target.h"
#include "vec.h"
+#include "solib-target.h"
#include "gdb_string.h"
so_list; it is only here during XML parsing. */
char *name;
+ /* The target can either specify segment bases or section bases, not
+ both. */
+
/* The base addresses for each independently relocatable segment of
this shared library. */
VEC(CORE_ADDR) *segment_bases;
+ /* The base addresses for each independently allocatable,
+ relocatable section of this shared library. */
+ VEC(CORE_ADDR) *section_bases;
+
/* The cached offsets for each section of this shared library,
- determined from SEGMENT_BASES. */
+ determined from SEGMENT_BASES, or SECTION_BASES. */
struct section_offsets *offsets;
};
#if !defined(HAVE_LIBEXPAT)
-static VEC(lm_info_p)
+static VEC(lm_info_p) *
solib_target_parse_libraries (const char *library)
{
static int have_warned;
ULONGEST *address_p = VEC_index (gdb_xml_value_s, attributes, 0)->value;
CORE_ADDR address = (CORE_ADDR) *address_p;
+ if (last->section_bases != NULL)
+ gdb_xml_error (parser,
+ _("Library list with both segments and sections"));
+
VEC_safe_push (CORE_ADDR, last->segment_bases, &address);
}
+static void
+library_list_start_section (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ VEC(lm_info_p) **list = user_data;
+ struct lm_info *last = VEC_last (lm_info_p, *list);
+ ULONGEST *address_p = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+ CORE_ADDR address = (CORE_ADDR) *address_p;
+
+ if (last->segment_bases != NULL)
+ gdb_xml_error (parser,
+ _("Library list with both segments and sections"));
+
+ VEC_safe_push (CORE_ADDR, last->section_bases, &address);
+}
+
/* Handle the start of a <library> element. */
static void
VEC_safe_push (lm_info_p, *list, item);
}
+static void
+library_list_end_library (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, const char *body_text)
+{
+ VEC(lm_info_p) **list = user_data;
+ struct lm_info *lm_info = VEC_last (lm_info_p, *list);
+ if (lm_info->segment_bases == NULL
+ && lm_info->section_bases == NULL)
+ gdb_xml_error (parser,
+ _("No segment or section bases defined"));
+}
+
+
/* Handle the start of a <library-list> element. */
static void
{
xfree (info->name);
VEC_free (CORE_ADDR, info->segment_bases);
+ VEC_free (CORE_ADDR, info->section_bases);
xfree (info);
}
VEC_free (lm_info_p, *result);
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
+const struct gdb_xml_attribute section_attributes[] = {
+ { "address", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
const struct gdb_xml_element library_children[] = {
- { "segment", segment_attributes, NULL, GDB_XML_EF_REPEATABLE,
+ { "segment", segment_attributes, NULL,
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
library_list_start_segment, NULL },
+ { "section", section_attributes, NULL,
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+ library_list_start_section, NULL },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
const struct gdb_xml_element library_list_children[] = {
{ "library", library_attributes, library_children,
GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
- library_list_start_library, NULL },
+ library_list_start_library, library_list_end_library },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
it any earlier, since we need to open the file first. */
if (so->lm_info->offsets == NULL)
{
- struct symfile_segment_data *data;
int num_sections = bfd_count_sections (so->abfd);
so->lm_info->offsets = xzalloc (SIZEOF_N_SECTION_OFFSETS (num_sections));
- data = get_symfile_segment_data (so->abfd);
- if (data == NULL)
- warning (_("Could not relocate shared library \"%s\": no segments"),
- so->so_name);
- else
+ if (so->lm_info->section_bases)
{
- ULONGEST orig_delta;
int i;
- int num_bases = VEC_length (CORE_ADDR, so->lm_info->segment_bases);
- CORE_ADDR *segment_bases = VEC_address (CORE_ADDR,
- so->lm_info->segment_bases);
-
- if (!symfile_map_offsets_to_segments (so->abfd, data,
- so->lm_info->offsets,
- num_bases, segment_bases))
- warning (_("Could not relocate shared library \"%s\": bad offsets"),
+ asection *sect;
+ int num_section_bases
+ = VEC_length (CORE_ADDR, so->lm_info->section_bases);
+ int num_alloc_sections = 0;
+
+ for (i = 0, sect = so->abfd->sections;
+ sect != NULL;
+ i++, sect = sect->next)
+ if ((bfd_get_section_flags (so->abfd, sect) & SEC_ALLOC))
+ num_alloc_sections++;
+
+ if (num_alloc_sections != num_section_bases)
+ warning (_("\
+Could not relocate shared library \"%s\": wrong number of ALLOC sections"),
so->so_name);
-
- /* Find the range of addresses to report for this library in
- "info sharedlibrary". Report any consecutive segments
- which were relocated as a single unit. */
- gdb_assert (num_bases > 0);
- orig_delta = segment_bases[0] - data->segment_bases[0];
-
- for (i = 1; i < data->num_segments; i++)
+ else
{
- /* If we have run out of offsets, assume all remaining segments
- have the same offset. */
- if (i >= num_bases)
- continue;
-
- /* If this segment does not have the same offset, do not include
- it in the library's range. */
- if (segment_bases[i] - data->segment_bases[i] != orig_delta)
- break;
+ int bases_index = 0;
+ int found_range = 0;
+ CORE_ADDR *section_bases;
+ section_bases = VEC_address (CORE_ADDR,
+ so->lm_info->section_bases);
+
+ so->addr_low = ~(CORE_ADDR) 0;
+ so->addr_high = 0;
+ for (i = 0, sect = so->abfd->sections;
+ sect != NULL;
+ i++, sect = sect->next)
+ {
+ if (!(bfd_get_section_flags (so->abfd, sect) & SEC_ALLOC))
+ continue;
+ if (bfd_section_size (so->abfd, sect) > 0)
+ {
+ CORE_ADDR low, high;
+ low = section_bases[i];
+ high = low + bfd_section_size (so->abfd, sect) - 1;
+
+ if (low < so->addr_low)
+ so->addr_low = low;
+ if (high > so->addr_high)
+ so->addr_high = high;
+ gdb_assert (so->addr_low <= so->addr_high);
+ found_range = 1;
+ }
+ so->lm_info->offsets->offsets[i] = section_bases[bases_index];
+ bases_index++;
+ }
+ if (!found_range)
+ so->addr_low = so->addr_high = 0;
+ gdb_assert (so->addr_low <= so->addr_high);
+ }
+ }
+ else if (so->lm_info->segment_bases)
+ {
+ struct symfile_segment_data *data;
+ data = get_symfile_segment_data (so->abfd);
+ if (data == NULL)
+ warning (_("\
+Could not relocate shared library \"%s\": no segments"), so->so_name);
+ else
+ {
+ ULONGEST orig_delta;
+ int i;
+ int num_bases;
+ CORE_ADDR *segment_bases;
+
+ num_bases = VEC_length (CORE_ADDR, so->lm_info->segment_bases);
+ segment_bases = VEC_address (CORE_ADDR,
+ so->lm_info->segment_bases);
+
+ if (!symfile_map_offsets_to_segments (so->abfd, data,
+ so->lm_info->offsets,
+ num_bases, segment_bases))
+ warning (_("\
+Could not relocate shared library \"%s\": bad offsets"), so->so_name);
+
+ /* Find the range of addresses to report for this library in
+ "info sharedlibrary". Report any consecutive segments
+ which were relocated as a single unit. */
+ gdb_assert (num_bases > 0);
+ orig_delta = segment_bases[0] - data->segment_bases[0];
+
+ for (i = 1; i < data->num_segments; i++)
+ {
+ /* If we have run out of offsets, assume all
+ remaining segments have the same offset. */
+ if (i >= num_bases)
+ continue;
+
+ /* If this segment does not have the same offset, do
+ not include it in the library's range. */
+ if (segment_bases[i] - data->segment_bases[i] != orig_delta)
+ break;
+ }
+
+ so->addr_low = segment_bases[0];
+ so->addr_high = (data->segment_bases[i - 1]
+ + data->segment_sizes[i - 1]
+ + orig_delta);
+ gdb_assert (so->addr_low <= so->addr_high);
+
+ free_symfile_segment_data (data);
}
-
- so->addr_low = segment_bases[0];
- so->addr_high = (data->segment_bases[i - 1]
- + data->segment_sizes[i - 1]
- + orig_delta);
- gdb_assert (so->addr_low <= so->addr_high);
-
- free_symfile_segment_data (data);
}
}
return in_plt_section (pc, NULL);
}
-static struct target_so_ops solib_target_so_ops;
+struct target_so_ops solib_target_so_ops;
extern initialize_file_ftype _initialize_solib_target; /* -Wmissing-prototypes */
= solib_target_open_symbol_file_object;
solib_target_so_ops.in_dynsym_resolve_code
= solib_target_in_dynsym_resolve_code;
-
- current_target_so_ops = &solib_target_so_ops;
}