/* Definitions for targets which report shared library events.
- Copyright (C) 2007
- Free Software Foundation, Inc.
+ Copyright (C) 2007-2019 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 "symtab.h"
#include "symfile.h"
#include "target.h"
-#include "vec.h"
-
-#include "gdb_string.h"
-
-DEF_VEC_O(CORE_ADDR);
+#include "gdbsupport/vec.h"
+#include "solib-target.h"
+#include <vector>
/* Private data for each loaded library. */
-struct lm_info
+struct lm_info_target : public lm_info_base
{
/* The library's name. The name is normally kept in the struct
so_list; it is only here during XML parsing. */
- char *name;
+ std::string 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;
+ std::vector<CORE_ADDR> segment_bases;
+
+ /* The base addresses for each independently allocatable,
+ relocatable section of this shared library. */
+ std::vector<CORE_ADDR> section_bases;
/* The cached offsets for each section of this shared library,
- determined from SEGMENT_BASES. */
- struct section_offsets *offsets;
+ determined from SEGMENT_BASES, or SECTION_BASES. */
+ section_offsets *offsets = NULL;
};
-typedef struct lm_info *lm_info_p;
-DEF_VEC_P(lm_info_p);
+typedef std::vector<std::unique_ptr<lm_info_target>> lm_info_vector;
#if !defined(HAVE_LIBEXPAT)
-static VEC(lm_info_p)
+static lm_info_vector
solib_target_parse_libraries (const char *library)
{
static int have_warned;
"at compile time"));
}
- return NULL;
+ return lm_info_vector ();
}
#else /* HAVE_LIBEXPAT */
static void
library_list_start_segment (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
- void *user_data, VEC(gdb_xml_value_s) *attributes)
+ void *user_data,
+ std::vector<gdb_xml_value> &attributes)
+{
+ lm_info_vector *list = (lm_info_vector *) user_data;
+ lm_info_target *last = list->back ().get ();
+ ULONGEST *address_p
+ = (ULONGEST *) xml_find_attribute (attributes, "address")->value.get ();
+ CORE_ADDR address = (CORE_ADDR) *address_p;
+
+ if (!last->section_bases.empty ())
+ gdb_xml_error (parser,
+ _("Library list with both segments and sections"));
+
+ last->segment_bases.push_back (address);
+}
+
+static void
+library_list_start_section (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ std::vector<gdb_xml_value> &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;
+ lm_info_vector *list = (lm_info_vector *) user_data;
+ lm_info_target *last = list->back ().get ();
+ ULONGEST *address_p
+ = (ULONGEST *) xml_find_attribute (attributes, "address")->value.get ();
+ CORE_ADDR address = (CORE_ADDR) *address_p;
+
+ if (!last->segment_bases.empty ())
+ gdb_xml_error (parser,
+ _("Library list with both segments and sections"));
- VEC_safe_push (CORE_ADDR, last->segment_bases, address_p);
+ last->section_bases.push_back (address);
}
/* Handle the start of a <library> element. */
static void
library_list_start_library (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
- void *user_data, VEC(gdb_xml_value_s) *attributes)
+ void *user_data,
+ std::vector<gdb_xml_value> &attributes)
{
- VEC(lm_info_p) **list = user_data;
- struct lm_info *item = XZALLOC (struct lm_info);
- const char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+ lm_info_vector *list = (lm_info_vector *) user_data;
+ lm_info_target *item = new lm_info_target;
+ item->name
+ = (const char *) xml_find_attribute (attributes, "name")->value.get ();
- item->name = xstrdup (name);
- VEC_safe_push (lm_info_p, *list, item);
+ list->emplace_back (item);
}
-/* Handle the start of a <library-list> element. */
-
static void
-library_list_start_list (struct gdb_xml_parser *parser,
- const struct gdb_xml_element *element,
- void *user_data, VEC(gdb_xml_value_s) *attributes)
+library_list_end_library (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, const char *body_text)
{
- char *version = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+ lm_info_vector *list = (lm_info_vector *) user_data;
+ lm_info_target *lm_info = list->back ().get ();
- if (strcmp (version, "1.0") != 0)
- gdb_xml_error (parser,
- _("Library list has unsupported version \"%s\""),
- version);
+ if (lm_info->segment_bases.empty () && lm_info->section_bases.empty ())
+ gdb_xml_error (parser, _("No segment or section bases defined"));
}
-/* Discard the constructed library list. */
+
+/* Handle the start of a <library-list> element. */
static void
-solib_target_free_library_list (void *p)
+library_list_start_list (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ std::vector<gdb_xml_value> &attributes)
{
- VEC(lm_info_p) **result = p;
- struct lm_info *info;
- int ix;
+ struct gdb_xml_value *version = xml_find_attribute (attributes, "version");
- for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++)
+ /* #FIXED attribute may be omitted, Expat returns NULL in such case. */
+ if (version != NULL)
{
- xfree (info->name);
- VEC_free (CORE_ADDR, info->segment_bases);
- xfree (info);
+ const char *string = (const char *) version->value.get ();
+
+ if (strcmp (string, "1.0") != 0)
+ gdb_xml_error (parser,
+ _("Library list has unsupported version \"%s\""),
+ string);
}
- VEC_free (lm_info_p, *result);
- *result = NULL;
}
/* The allowed elements and attributes for an XML library list.
The root element is a <library-list>. */
-const struct gdb_xml_attribute segment_attributes[] = {
+static const struct gdb_xml_attribute segment_attributes[] = {
+ { "address", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static 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,
+static const struct gdb_xml_element library_children[] = {
+ { "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_attribute library_attributes[] = {
+static const struct gdb_xml_attribute library_attributes[] = {
{ "name", GDB_XML_AF_NONE, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
-const struct gdb_xml_element library_list_children[] = {
+static 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 }
};
-const struct gdb_xml_attribute library_list_attributes[] = {
- { "version", GDB_XML_AF_NONE, NULL, NULL },
+static const struct gdb_xml_attribute library_list_attributes[] = {
+ { "version", GDB_XML_AF_OPTIONAL, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
-const struct gdb_xml_element library_list_elements[] = {
+static const struct gdb_xml_element library_list_elements[] = {
{ "library-list", library_list_attributes, library_list_children,
GDB_XML_EF_NONE, library_list_start_list, NULL },
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
-static VEC(lm_info_p) *
+static lm_info_vector
solib_target_parse_libraries (const char *library)
{
- struct gdb_xml_parser *parser;
- VEC(lm_info_p) *result = NULL;
- struct cleanup *before_deleting_result, *back_to;
-
- back_to = make_cleanup (null_cleanup, NULL);
- parser = gdb_xml_create_parser_and_cleanup (_("target library list"),
- library_list_elements, &result);
- gdb_xml_use_dtd (parser, "library-list.dtd");
+ lm_info_vector result;
- before_deleting_result = make_cleanup (solib_target_free_library_list,
- &result);
-
- if (gdb_xml_parse (parser, library) == 0)
- /* Parsed successfully, don't need to delete the result. */
- discard_cleanups (before_deleting_result);
+ if (gdb_xml_parse_quick (_("target library list"), "library-list.dtd",
+ library_list_elements, library, &result) == 0)
+ {
+ /* Parsed successfully. */
+ return result;
+ }
- do_cleanups (back_to);
+ result.clear ();
return result;
}
#endif
solib_target_current_sos (void)
{
struct so_list *new_solib, *start = NULL, *last = NULL;
- const char *library_document;
- VEC(lm_info_p) *library_list;
- struct lm_info *info;
- int ix;
/* Fetch the list of shared libraries. */
- library_document = target_read_stralloc (¤t_target,
- TARGET_OBJECT_LIBRARIES,
- NULL);
- if (library_document == NULL)
+ gdb::optional<gdb::char_vector> library_document
+ = target_read_stralloc (current_top_target (), TARGET_OBJECT_LIBRARIES,
+ NULL);
+ if (!library_document)
return NULL;
/* Parse the list. */
- library_list = solib_target_parse_libraries (library_document);
- if (library_list == NULL)
+ lm_info_vector library_list
+ = solib_target_parse_libraries (library_document->data ());
+
+ if (library_list.empty ())
return NULL;
/* Build a struct so_list for each entry on the list. */
- for (ix = 0; VEC_iterate (lm_info_p, library_list, ix, info); ix++)
+ for (auto &&info : library_list)
{
- new_solib = XZALLOC (struct so_list);
- strncpy (new_solib->so_name, info->name, SO_NAME_MAX_PATH_SIZE - 1);
+ new_solib = XCNEW (struct so_list);
+ strncpy (new_solib->so_name, info->name.c_str (),
+ SO_NAME_MAX_PATH_SIZE - 1);
new_solib->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
- strncpy (new_solib->so_original_name, info->name,
+ strncpy (new_solib->so_original_name, info->name.c_str (),
SO_NAME_MAX_PATH_SIZE - 1);
new_solib->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
- new_solib->lm_info = info;
/* We no longer need this copy of the name. */
- xfree (info->name);
- info->name = NULL;
+ info->name.clear ();
+
+ new_solib->lm_info = info.release ();
/* Add it to the list. */
if (!start)
}
}
- /* Free the library list, but not its members. */
- VEC_free (lm_info_p, library_list);
-
return start;
}
static void
-solib_target_special_symbol_handling (void)
-{
- /* Nothing needed. */
-}
-
-static void
-solib_target_solib_create_inferior_hook (void)
+solib_target_solib_create_inferior_hook (int from_tty)
{
/* Nothing needed. */
}
static void
solib_target_free_so (struct so_list *so)
{
- gdb_assert (so->lm_info->name == NULL);
- xfree (so->lm_info->offsets);
- VEC_free (CORE_ADDR, so->lm_info->segment_bases);
- xfree (so->lm_info);
+ lm_info_target *li = (lm_info_target *) so->lm_info;
+
+ gdb_assert (li->name.empty ());
+
+ delete li;
}
static void
solib_target_relocate_section_addresses (struct so_list *so,
- struct section_table *sec)
+ struct target_section *sec)
{
- int flags = bfd_get_section_flags (sec->bfd, sec->the_bfd_section);
CORE_ADDR offset;
+ lm_info_target *li = (lm_info_target *) so->lm_info;
/* Build the offset table only once per object file. We can not do
it any earlier, since we need to open the file first. */
- if (so->lm_info->offsets == NULL)
+ if (li->offsets == NULL)
{
- struct symfile_segment_data *data;
- int num_sections = bfd_count_sections (so->abfd);
+ int num_sections = gdb_bfd_count_sections (so->abfd);
- so->lm_info->offsets = xzalloc (SIZEOF_N_SECTION_OFFSETS (num_sections));
+ li->offsets
+ = ((struct section_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 (!li->section_bases.empty ())
{
- 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_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 != li->section_bases.size ())
+ 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;
+
+ 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 = li->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;
+ }
+ li->offsets->offsets[i] = li->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 (!li->segment_bases.empty ())
+ {
+ struct symfile_segment_data *data;
- so->addr_low = segment_bases[0];
- so->addr_high = (data->segment_bases[i - 1]
- + data->segment_sizes[i - 1]
- /* FIXME this must be needed! + orig_delta */);
-
- free_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;
+
+ if (!symfile_map_offsets_to_segments (so->abfd, data, li->offsets,
+ li->segment_bases.size (),
+ li->segment_bases.data ()))
+ 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 (li->segment_bases.size () > 0);
+ orig_delta = li->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 >= li->segment_bases.size ())
+ continue;
+
+ /* If this segment does not have the same offset, do
+ not include it in the library's range. */
+ if (li->segment_bases[i] - data->segment_bases[i]
+ != orig_delta)
+ break;
+ }
+
+ so->addr_low = li->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);
+ }
}
}
- offset = so->lm_info->offsets->offsets[sec->the_bfd_section->index];
+ offset = li->offsets->offsets[gdb_bfd_section_index
+ (sec->the_bfd_section->owner,
+ sec->the_bfd_section)];
sec->addr += offset;
sec->endaddr += offset;
}
static int
-solib_target_open_symbol_file_object (void *from_ttyp)
+solib_target_open_symbol_file_object (int from_tty)
{
/* We can't locate the main symbol file based on the target's
knowledge; the user has to specify it. */
/* We don't have a range of addresses for the dynamic linker; there
may not be one in the program's address space. So only report
PLT entries (which may be import stubs). */
- return in_plt_section (pc, NULL);
+ return in_plt_section (pc);
}
-static struct target_so_ops solib_target_so_ops;
-
-extern initialize_file_ftype _initialize_solib_target; /* -Wmissing-prototypes */
+struct target_so_ops solib_target_so_ops;
void
_initialize_solib_target (void)
solib_target_so_ops.clear_solib = solib_target_clear_solib;
solib_target_so_ops.solib_create_inferior_hook
= solib_target_solib_create_inferior_hook;
- solib_target_so_ops.special_symbol_handling
- = solib_target_special_symbol_handling;
solib_target_so_ops.current_sos = solib_target_current_sos;
solib_target_so_ops.open_symbol_file_object
= solib_target_open_symbol_file_object;
solib_target_so_ops.in_dynsym_resolve_code
= solib_target_in_dynsym_resolve_code;
+ solib_target_so_ops.bfd_open = solib_bfd_open;
- current_target_so_ops = &solib_target_so_ops;
+ /* Set current_target_so_ops to solib_target_so_ops if not already
+ set. */
+ if (current_target_so_ops == 0)
+ current_target_so_ops = &solib_target_so_ops;
}