[02/10] Make various lm_info implementations inherit from a base class

Message ID 20170426224706.27988-3-simon.marchi@ericsson.com
State New, archived
Headers

Commit Message

Simon Marchi April 26, 2017, 10:46 p.m. UTC
  From: Simon Marchi <simon.marchi@polymtl.ca>

The lm_info structure is used to store target specific information about
mapped libraries.  It is currently defined as an opaque type in solist.h
and a pointer to it is included in solist, the target-agnostic object
representing a loaded shared library.  Multiple targets define their own
implementation of lm_info.

In anticipation of using C++ stuff (e.g. vector) in the lm_info objects,
we first need to avoid different definitions of classes with the same
name (which violates the one definition rule).  This patch does it by
having a base class (lm_info_base) from which all the specific lm_info
derive.  Each implementation is renamed to something that makes sense
(e.g. lm_info_aix for AIX).  The next logical step would probably be to
derive directly from so_list, but it's not really obvious, so I'll keep
that for another day.

One special case is the Neutrino (nto) support.  It uses SVR4-style
libraries, but overrides some methods.  To do that, it needed to have
its own copy of SVR4's lm_info structure in nto-tdep.c, because it was
just not possible to put it in solib-svr4.h and include that file.  Over
time, that copy got out of sync, which is still the case today.  I can
only assume that the lm_addr function in nto-tdep.c is broken right now.
The first field of the old lm_info was a pointer (gdb_byte *), whereas
in the new lm_info it's an address in the inferior (CORE_ADDR).  Trying
to use that field today probably results in a crash.  With this
refactor, it's now possible to put lm_info_svr4 in solib-svr4.h and just
include it.  I have adapted the code in nto-tdep.c to that it builds,
but it's probably not correct.  Since I don't have the knowledge nor
setup to try this on Neutrino, somebody else would have to fix it.  But
I am confident that I am not making things worse than they already are.

gdb/ChangeLog:

	* solist.h (struct lm_info): Remove.
	(struct lm_info_base): New class.
	(struct so_list) <lm_info>: Change type to lm_info_base *.
	* nto-tdep.c (struct lm_info): Remove.
	(lm_addr): Adjust.
	* solib-aix.c (struct lm_info): Rename to ...
	(struct lm_info_aix): ... this.  Extend lm_info_base.
	(lm_info_p): Rename to ...
	(lm_info_aix_p): ... this, and adjust.
	(solib_aix_new_lm_info, solib_aix_xfree_lm_info,
	solib_aix_parse_libraries, library_list_start_library,
	solib_aix_free_library_list, solib_aix_parse_libraries,
	solib_aix_get_library_list,
	solib_aix_relocate_section_addresses, solib_aix_free_so,
	solib_aix_get_section_offsets,
	solib_aix_solib_create_inferior_hook, solib_aix_current_sos):
	Adjust.
	(struct solib_aix_inferior_data) <library_list>: Adjust.
	* solib-darwin.c (struct lm_info): Rename to ...
	(struct lm_info_darwin): ... this.  Extend lm_info_base.
	(darwin_current_sos, darwin_relocate_section_addresses): Adjust.
	* solib-dsbt.c (struct lm_info): Rename to ...
	(struct lm_info_dsbt): ... this.  Extend lm_info_base.
	(struct dsbt_info) <main_executable_lm_info): Adjust.
	(dsbt_current_sos, dsbt_relocate_main_executable, dsbt_free_so,
	dsbt_relocate_section_addresses): Adjust.
	* solib-frv.c (struct lm_info): Rename to ...
	(struct lm_info_frv): ... this.  Extend lm_info_base.
	(main_executable_lm_info): Adjust.
	(frv_current_sos, frv_relocate_main_executable, frv_free_so,
	frv_relocate_section_addresses, frv_fdpic_find_global_pointer,
	find_canonical_descriptor_in_load_object,
	frv_fdpic_find_canonical_descriptor): Adjust.
	* solib-svr4.c (struct lm_info): Move to solib-svr4.h, renamed
	to lm_info_svr4.
	(lm_info_read, lm_addr_check, svr4_keep_data_in_core,
	svr4_clear_so, svr4_copy_library_list,
	library_list_start_library, svr4_default_sos, svr4_read_so_list,
	svr4_current_sos, svr4_fetch_objfile_link_map,
	solist_update_incremental): Adjust.
	* solib-svr4.h (struct lm_info_svr4): Move here from
	solib-svr4.c.
	* solib-target.c (struct lm_info): Rename to ...
	(struct lm_info_target): ... this.  Extend lm_info_base.
	(lm_info_p): Rename to ...
	(lm_info_target_p): ... this.
	(solib_target_parse_libraries, library_list_start_segment,
	library_list_start_section, library_list_start_library,
	library_list_end_library, solib_target_free_library_list,
	solib_target_current_sos, solib_target_free_so,
	solib_target_relocate_section_addresses): Adjust.
	* windows-nat.c (struct lm_info): Rename to ...
	(struct lm_info_windows): ... this.  Extend lm_info_base.
	(windows_make_so, handle_load_dll, handle_unload_dll,
	windows_xfer_shared_libraries): Adjust.
---
 gdb/nto-tdep.c     |  35 +----------------
 gdb/solib-aix.c    |  62 +++++++++++++++---------------
 gdb/solib-darwin.c |  13 ++++---
 gdb/solib-dsbt.c   |  22 ++++++-----
 gdb/solib-frv.c    |  49 ++++++++++++-----------
 gdb/solib-svr4.c   | 111 +++++++++++++++++++++++++----------------------------
 gdb/solib-svr4.h   |  23 +++++++++++
 gdb/solib-target.c |  85 ++++++++++++++++++++--------------------
 gdb/solist.h       |  10 +++--
 gdb/windows-nat.c  |  45 ++++++++++++++--------
 10 files changed, 233 insertions(+), 222 deletions(-)
  

Comments

Pedro Alves April 28, 2017, 3:57 p.m. UTC | #1
On 04/26/2017 11:46 PM, Simon Marchi wrote:
> From: Simon Marchi <simon.marchi@polymtl.ca>
> 
> The lm_info structure is used to store target specific information about
> mapped libraries.  It is currently defined as an opaque type in solist.h
> and a pointer to it is included in solist, the target-agnostic object
> representing a loaded shared library.  Multiple targets define their own
> implementation of lm_info.
> 
> In anticipation of using C++ stuff (e.g. vector) in the lm_info objects,
> we first need to avoid different definitions of classes with the same
> name (which violates the one definition rule).  This patch does it by
> having a base class (lm_info_base) from which all the specific lm_info
> derive.  Each implementation is renamed to something that makes sense
> (e.g. lm_info_aix for AIX).  The next logical step would probably be to
> derive directly from so_list, but it's not really obvious, so I'll keep
> that for another day.
> 
> One special case is the Neutrino (nto) support.  It uses SVR4-style
> libraries, but overrides some methods.  To do that, it needed to have
> its own copy of SVR4's lm_info structure in nto-tdep.c, because it was
> just not possible to put it in solib-svr4.h and include that file.  Over
> time, that copy got out of sync, which is still the case today.  I can
> only assume that the lm_addr function in nto-tdep.c is broken right now.
> The first field of the old lm_info was a pointer (gdb_byte *), whereas
> in the new lm_info it's an address in the inferior (CORE_ADDR).  Trying
> to use that field today probably results in a crash.  With this
> refactor, it's now possible to put lm_info_svr4 in solib-svr4.h and just
> include it.  I have adapted the code in nto-tdep.c to that it builds,
> but it's probably not correct.  Since I don't have the knowledge nor
> setup to try this on Neutrino, somebody else would have to fix it.  But
> I am confident that I am not making things worse than they already are.

LGTM.

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/nto-tdep.c b/gdb/nto-tdep.c
index 8f8d1d5384..f9959ca9e0 100644
--- a/gdb/nto-tdep.c
+++ b/gdb/nto-tdep.c
@@ -239,43 +239,12 @@  nto_parse_redirection (char *pargv[], const char **pin, const char **pout,
   return argv;
 }
 
-/* The struct lm_info, lm_addr, and nto_truncate_ptr are copied from
-   solib-svr4.c to support nto_relocate_section_addresses
-   which is different from the svr4 version.  */
-
-/* Link map info to include in an allocated so_list entry */
-
-struct lm_info
-  {
-    /* Pointer to copy of link map from inferior.  The type is char *
-       rather than void *, so that we may use byte offsets to find the
-       various fields without the need for a cast.  */
-    gdb_byte *lm;
-
-    /* Amount by which addresses in the binary should be relocated to
-       match the inferior.  This could most often be taken directly
-       from lm, but when prelinking is involved and the prelink base
-       address changes, we may need a different offset, we want to
-       warn about the difference and compute it only once.  */
-    CORE_ADDR l_addr;
-
-    /* The target location of lm.  */
-    CORE_ADDR lm_addr;
-  };
-
-
 static CORE_ADDR
 lm_addr (struct so_list *so)
 {
-  if (so->lm_info->l_addr == (CORE_ADDR)-1)
-    {
-      struct link_map_offsets *lmo = nto_fetch_link_map_offsets ();
-      struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
+  lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
 
-      so->lm_info->l_addr =
-	extract_typed_address (so->lm_info->lm + lmo->l_addr_offset, ptr_type);
-    }
-  return so->lm_info->l_addr;
+  return li->l_addr;
 }
 
 static CORE_ADDR
diff --git a/gdb/solib-aix.c b/gdb/solib-aix.c
index 66add03054..54b8c38032 100644
--- a/gdb/solib-aix.c
+++ b/gdb/solib-aix.c
@@ -33,7 +33,7 @@  static int solib_aix_debug;
 
 /* Our private data in struct so_list.  */
 
-struct lm_info
+struct lm_info_aix : public lm_info_base
 {
   /* The name of the file mapped by the loader.  Apart from the entry
      for the main executable, this is usually a shared library (which,
@@ -58,17 +58,17 @@  struct lm_info
   ULONGEST data_size;
 };
 
-typedef struct lm_info *lm_info_p;
-DEF_VEC_P(lm_info_p);
+typedef lm_info_aix *lm_info_aix_p;
+DEF_VEC_P(lm_info_aix_p);
 
 /* Return a deep copy of the given struct lm_info object.  */
 
-static struct lm_info *
-solib_aix_new_lm_info (struct lm_info *info)
+static lm_info_aix *
+solib_aix_new_lm_info (lm_info_aix *info)
 {
-  struct lm_info *result = XNEW (struct lm_info);
+  lm_info_aix *result = XCNEW (lm_info_aix);
 
-  memcpy (result, info, sizeof (struct lm_info));
+  memcpy (result, info, sizeof (lm_info_aix));
   result->filename = xstrdup (info->filename);
   if (info->member_name != NULL)
     result->member_name = xstrdup (info->member_name);
@@ -79,7 +79,7 @@  solib_aix_new_lm_info (struct lm_info *info)
 /* Free the memory allocated for the given lm_info.  */
 
 static void
-solib_aix_xfree_lm_info (struct lm_info *info)
+solib_aix_xfree_lm_info (lm_info_aix *info)
 {
   xfree (info->filename);
   xfree (info->member_name);
@@ -98,7 +98,7 @@  struct solib_aix_inferior_data
      the same principles applied to shared libraries also apply
      to the main executable.  So it's simpler to keep it as part
      of this list.  */
-  VEC (lm_info_p) *library_list;
+  VEC (lm_info_aix_p) *library_list;
 };
 
 /* Key to our per-inferior data.  */
@@ -127,7 +127,7 @@  get_solib_aix_inferior_data (struct inferior *inf)
 
 /* Dummy implementation if XML support is not compiled in.  */
 
-static VEC (lm_info_p) *
+static VEC (lm_info_aix_p) *
 solib_aix_parse_libraries (const char *library)
 {
   static int have_warned;
@@ -161,8 +161,8 @@  library_list_start_library (struct gdb_xml_parser *parser,
 			    void *user_data,
 			    VEC (gdb_xml_value_s) *attributes)
 {
-  VEC (lm_info_p) **list = (VEC (lm_info_p) **) user_data;
-  struct lm_info *item = XCNEW (struct lm_info);
+  VEC (lm_info_aix_p) **list = (VEC (lm_info_aix_p) **) user_data;
+  lm_info_aix *item = XCNEW (lm_info_aix);
   struct gdb_xml_value *attr;
 
   attr = xml_find_attribute (attributes, "name");
@@ -184,7 +184,7 @@  library_list_start_library (struct gdb_xml_parser *parser,
   attr = xml_find_attribute (attributes, "data_size");
   item->data_size = * (ULONGEST *) attr->value;
 
-  VEC_safe_push (lm_info_p, *list, item);
+  VEC_safe_push (lm_info_aix_p, *list, item);
 }
 
 /* Handle the start of a <library-list-aix> element.  */
@@ -207,16 +207,16 @@  library_list_start_list (struct gdb_xml_parser *parser,
 static void
 solib_aix_free_library_list (void *p)
 {
-  VEC (lm_info_p) **result = (VEC (lm_info_p) **) p;
-  struct lm_info *info;
+  VEC (lm_info_aix_p) **result = (VEC (lm_info_aix_p) **) p;
+  lm_info_aix *info;
   int ix;
 
   if (solib_aix_debug)
     fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_library_list\n");
 
-  for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++)
+  for (ix = 0; VEC_iterate (lm_info_aix_p, *result, ix, info); ix++)
     solib_aix_xfree_lm_info (info);
-  VEC_free (lm_info_p, *result);
+  VEC_free (lm_info_aix_p, *result);
   *result = NULL;
 }
 
@@ -256,14 +256,14 @@  static const struct gdb_xml_element library_list_elements[] =
 };
 
 /* Parse LIBRARY, a string containing the loader info in XML format,
-   and return an lm_info_p vector.
+   and return an lm_info_aix_p vector.
 
    Return NULL if the parsing failed.  */
 
-static VEC (lm_info_p) *
+static VEC (lm_info_aix_p) *
 solib_aix_parse_libraries (const char *library)
 {
-  VEC (lm_info_p) *result = NULL;
+  VEC (lm_info_aix_p) *result = NULL;
   struct cleanup *back_to = make_cleanup (solib_aix_free_library_list,
                                           &result);
 
@@ -291,7 +291,7 @@  solib_aix_parse_libraries (const char *library)
    is not NULL, then print a warning including WARNING_MSG and
    a description of the error.  */
 
-static VEC (lm_info_p) *
+static VEC (lm_info_aix_p) *
 solib_aix_get_library_list (struct inferior *inf, const char *warning_msg)
 {
   struct solib_aix_inferior_data *data;
@@ -394,7 +394,7 @@  solib_aix_relocate_section_addresses (struct so_list *so,
   struct bfd_section *bfd_sect = sec->the_bfd_section;
   bfd *abfd = bfd_sect->owner;
   const char *section_name = bfd_section_name (abfd, bfd_sect);
-  struct lm_info *info = so->lm_info;
+  lm_info_aix *info = (lm_info_aix *) so->lm_info;
 
   if (strcmp (section_name, ".text") == 0)
     {
@@ -446,7 +446,7 @@  solib_aix_free_so (struct so_list *so)
   if (solib_aix_debug)
     fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_so (%s)\n",
 			so->so_name);
-  solib_aix_xfree_lm_info (so->lm_info);
+  solib_aix_xfree_lm_info ((lm_info_aix *) so->lm_info);
 }
 
 /* Implement the "clear_solib" target_so_ops method.  */
@@ -465,7 +465,7 @@  solib_aix_clear_solib (void)
 
 static struct section_offsets *
 solib_aix_get_section_offsets (struct objfile *objfile,
-			       struct lm_info *info)
+			       lm_info_aix *info)
 {
   struct section_offsets *offsets;
   bfd *abfd = objfile->obfd;
@@ -519,8 +519,8 @@  static void
 solib_aix_solib_create_inferior_hook (int from_tty)
 {
   const char *warning_msg = "unable to relocate main executable";
-  VEC (lm_info_p) *library_list;
-  struct lm_info *exec_info;
+  VEC (lm_info_aix_p) *library_list;
+  lm_info_aix *exec_info;
 
   /* We need to relocate the main executable...  */
 
@@ -529,13 +529,13 @@  solib_aix_solib_create_inferior_hook (int from_tty)
   if (library_list == NULL)
     return;  /* Warning already printed.  */
 
-  if (VEC_length (lm_info_p, library_list) < 1)
+  if (VEC_length (lm_info_aix_p, library_list) < 1)
     {
       warning (_("unable to relocate main executable (no info from loader)"));
       return;
     }
 
-  exec_info = VEC_index (lm_info_p, library_list, 0);
+  exec_info = VEC_index (lm_info_aix_p, library_list, 0);
 
   if (symfile_objfile != NULL)
     {
@@ -554,8 +554,8 @@  static struct so_list *
 solib_aix_current_sos (void)
 {
   struct so_list *start = NULL, *last = NULL;
-  VEC (lm_info_p) *library_list;
-  struct lm_info *info;
+  VEC (lm_info_aix_p) *library_list;
+  lm_info_aix *info;
   int ix;
 
   library_list = solib_aix_get_library_list (current_inferior (), NULL);
@@ -565,7 +565,7 @@  solib_aix_current_sos (void)
   /* Build a struct so_list for each entry on the list.
      We skip the first entry, since this is the entry corresponding
      to the main executable, not a shared library.  */
-  for (ix = 1; VEC_iterate (lm_info_p, library_list, ix, info); ix++)
+  for (ix = 1; VEC_iterate (lm_info_aix_p, library_list, ix, info); ix++)
     {
       struct so_list *new_solib = XCNEW (struct so_list);
       char *so_name;
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index c507e13caf..03211cfb92 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -153,7 +153,7 @@  darwin_load_image_infos (struct darwin_info *info)
 
 /* Link map info to include in an allocated so_list entry.  */
 
-struct lm_info
+struct lm_info_darwin : public lm_info_base
 {
   /* The target location of lm.  */
   CORE_ADDR lm_addr;
@@ -296,13 +296,14 @@  darwin_current_sos (void)
       newobj = XCNEW (struct so_list);
       old_chain = make_cleanup (xfree, newobj);
 
-      newobj->lm_info = XCNEW (struct lm_info);
+      lm_info_darwin *li = XCNEW (lm_info_darwin);
+      newobj->lm_info = li;
 
       strncpy (newobj->so_name, file_path, SO_NAME_MAX_PATH_SIZE - 1);
       newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
       strcpy (newobj->so_original_name, newobj->so_name);
       xfree (file_path);
-      newobj->lm_info->lm_addr = load_addr;
+      li->lm_addr = load_addr;
 
       if (head == NULL)
 	head = newobj;
@@ -587,8 +588,10 @@  static void
 darwin_relocate_section_addresses (struct so_list *so,
 				   struct target_section *sec)
 {
-  sec->addr += so->lm_info->lm_addr;
-  sec->endaddr += so->lm_info->lm_addr;
+  lm_info_darwin *li = (lm_info_darwin *) so->lm_info;
+
+  sec->addr += li->lm_addr;
+  sec->endaddr += li->lm_addr;
 
   /* Best effort to set addr_high/addr_low.  This is used only by
      'info sharedlibary'.  */
diff --git a/gdb/solib-dsbt.c b/gdb/solib-dsbt.c
index c4071066f1..6d410ac90b 100644
--- a/gdb/solib-dsbt.c
+++ b/gdb/solib-dsbt.c
@@ -123,7 +123,7 @@  struct ext_link_map
 
 /* Link map info to include in an allocated so_list entry */
 
-struct lm_info
+struct lm_info_dsbt : public lm_info_base
 {
   /* The loadmap, digested into an easier to use form.  */
   struct int_elf32_dsbt_loadmap *map;
@@ -137,7 +137,7 @@  struct dsbt_info
      of loaded shared objects.  ``main_executable_lm_info'' provides
      a way to get at this information so that it doesn't need to be
      frequently recomputed.  Initialized by dsbt_relocate_main_executable.  */
-  struct lm_info *main_executable_lm_info;
+  struct lm_info_dsbt *main_executable_lm_info;
 
   /* Load maps for the main executable and the interpreter.  These are obtained
      from ptrace.  They are the starting point for getting into the program,
@@ -711,8 +711,9 @@  dsbt_current_sos (void)
 	    }
 
 	  sop = XCNEW (struct so_list);
-	  sop->lm_info = XCNEW (struct lm_info);
-	  sop->lm_info->map = loadmap;
+	  lm_info_dsbt *li = XCNEW (lm_info_dsbt);
+	  sop->lm_info = li;
+	  li->map = loadmap;
 	  /* Fetch the name.  */
 	  addr = extract_unsigned_integer (lm_buf.l_name,
 					   sizeof (lm_buf.l_name),
@@ -930,7 +931,7 @@  dsbt_relocate_main_executable (void)
   ldm = info->exec_loadmap;
 
   xfree (info->main_executable_lm_info);
-  info->main_executable_lm_info = XCNEW (struct lm_info);
+  info->main_executable_lm_info = XCNEW (lm_info_dsbt);
   info->main_executable_lm_info->map = ldm;
 
   new_offsets = XCNEWVEC (struct section_offsets,
@@ -1016,8 +1017,10 @@  dsbt_clear_solib (void)
 static void
 dsbt_free_so (struct so_list *so)
 {
-  xfree (so->lm_info->map);
-  xfree (so->lm_info);
+  lm_info_dsbt *li = (lm_info_dsbt *) so->lm_info;
+
+  xfree (li->map);
+  xfree (li);
 }
 
 static void
@@ -1025,9 +1028,8 @@  dsbt_relocate_section_addresses (struct so_list *so,
 				 struct target_section *sec)
 {
   int seg;
-  struct int_elf32_dsbt_loadmap *map;
-
-  map = so->lm_info->map;
+  lm_info_dsbt *li = (lm_info_dsbt *) so->lm_info;
+  int_elf32_dsbt_loadmap *map = li->map;
 
   for (seg = 0; seg < map->nsegs; seg++)
     {
diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c
index e8d5f20d4f..0108d97815 100644
--- a/gdb/solib-frv.c
+++ b/gdb/solib-frv.c
@@ -202,7 +202,7 @@  struct ext_link_map
 
 /* Link map info to include in an allocated so_list entry.  */
 
-struct lm_info
+struct lm_info_frv : public lm_info_base
   {
     /* The loadmap, digested into an easier to use form.  */
     struct int_elf32_fdpic_loadmap *map;
@@ -231,7 +231,7 @@  struct lm_info
    of loaded shared objects.  ``main_executable_lm_info'' provides
    a way to get at this information so that it doesn't need to be
    frequently recomputed.  Initialized by frv_relocate_main_executable().  */
-static struct lm_info *main_executable_lm_info;
+static lm_info_frv *main_executable_lm_info;
 
 static void frv_relocate_main_executable (void);
 static CORE_ADDR main_got (void);
@@ -389,10 +389,11 @@  frv_current_sos (void)
 	    }
 
 	  sop = XCNEW (struct so_list);
-	  sop->lm_info = XCNEW (struct lm_info);
-	  sop->lm_info->map = loadmap;
-	  sop->lm_info->got_value = got_addr;
-	  sop->lm_info->lm_addr = lm_addr;
+	  lm_info_frv *li = XCNEW (lm_info_frv);
+	  sop->lm_info = li;
+	  li->map = loadmap;
+	  li->got_value = got_addr;
+	  li->lm_addr = lm_addr;
 	  /* Fetch the name.  */
 	  addr = extract_unsigned_integer (lm_buf.l_name,
 					   sizeof (lm_buf.l_name),
@@ -783,7 +784,7 @@  frv_relocate_main_executable (void)
 
   if (main_executable_lm_info)
     xfree (main_executable_lm_info);
-  main_executable_lm_info = XCNEW (struct lm_info);
+  main_executable_lm_info = XCNEW (lm_info_frv);
   main_executable_lm_info->map = ldm;
 
   new_offsets = XCNEWVEC (struct section_offsets,
@@ -870,10 +871,12 @@  frv_clear_solib (void)
 static void
 frv_free_so (struct so_list *so)
 {
-  xfree (so->lm_info->map);
-  xfree (so->lm_info->dyn_syms);
-  xfree (so->lm_info->dyn_relocs);
-  xfree (so->lm_info);
+  lm_info_frv *li = (lm_info_frv *) so->lm_info;
+
+  xfree (li->map);
+  xfree (li->dyn_syms);
+  xfree (li->dyn_relocs);
+  xfree (li);
 }
 
 static void
@@ -881,9 +884,8 @@  frv_relocate_section_addresses (struct so_list *so,
                                  struct target_section *sec)
 {
   int seg;
-  struct int_elf32_fdpic_loadmap *map;
-
-  map = so->lm_info->map;
+  lm_info_frv *li = (lm_info_frv *) so->lm_info;
+  int_elf32_fdpic_loadmap *map = li->map;
 
   for (seg = 0; seg < map->nsegs; seg++)
     {
@@ -926,15 +928,14 @@  frv_fdpic_find_global_pointer (CORE_ADDR addr)
   while (so)
     {
       int seg;
-      struct int_elf32_fdpic_loadmap *map;
-
-      map = so->lm_info->map;
+      lm_info_frv *li = (lm_info_frv *) so->lm_info;
+      int_elf32_fdpic_loadmap *map = li->map;
 
       for (seg = 0; seg < map->nsegs; seg++)
 	{
 	  if (map->segs[seg].addr <= addr
 	      && addr < map->segs[seg].addr + map->segs[seg].p_memsz)
-	    return so->lm_info->got_value;
+	    return li->got_value;
 	}
 
       so = so->next;
@@ -947,7 +948,7 @@  frv_fdpic_find_global_pointer (CORE_ADDR addr)
 
 /* Forward declarations for frv_fdpic_find_canonical_descriptor().  */
 static CORE_ADDR find_canonical_descriptor_in_load_object
-  (CORE_ADDR, CORE_ADDR, const char *, bfd *, struct lm_info *);
+  (CORE_ADDR, CORE_ADDR, const char *, bfd *, lm_info_frv *);
 
 /* Given a function entry point, attempt to find the canonical descriptor
    associated with that entry point.  Return 0 if no canonical descriptor
@@ -987,8 +988,10 @@  frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point)
       so = master_so_list ();
       while (so)
 	{
+	  lm_info_frv *li = (lm_info_frv *) so->lm_info;
+
 	  addr = find_canonical_descriptor_in_load_object
-		   (entry_point, got_value, name, so->abfd, so->lm_info);
+		   (entry_point, got_value, name, so->abfd, li);
 
 	  if (addr != 0)
 	    break;
@@ -1003,7 +1006,7 @@  frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point)
 static CORE_ADDR
 find_canonical_descriptor_in_load_object
   (CORE_ADDR entry_point, CORE_ADDR got_value, const char *name, bfd *abfd,
-   struct lm_info *lm)
+   lm_info_frv *lm)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
   arelent *rel;
@@ -1141,8 +1144,10 @@  frv_fetch_objfile_link_map (struct objfile *objfile)
      of shared libraries.  */
   for (so = master_so_list (); so; so = so->next)
     {
+      lm_info_frv *li = (lm_info_frv *) so->lm_info;
+
       if (so->objfile == objfile)
-	return so->lm_info->lm_addr;
+	return li->lm_addr;
     }
 
   /* Not found!  */
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 4cb6127af3..6098d505da 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -51,27 +51,6 @@  static int svr4_have_link_map_offsets (void);
 static void svr4_relocate_main_executable (void);
 static void svr4_free_library_list (void *p_list);
 
-/* Link map info to include in an allocated so_list entry.  */
-
-struct lm_info
-  {
-    /* Amount by which addresses in the binary should be relocated to
-       match the inferior.  The direct inferior value is L_ADDR_INFERIOR.
-       When prelinking is involved and the prelink base address changes,
-       we may need a different offset - the recomputed offset is in L_ADDR.
-       It is commonly the same value.  It is cached as we want to warn about
-       the difference and compute it only once.  L_ADDR is valid
-       iff L_ADDR_P.  */
-    CORE_ADDR l_addr, l_addr_inferior;
-    unsigned int l_addr_p : 1;
-
-    /* The target location of lm.  */
-    CORE_ADDR lm_addr;
-
-    /* Values read in from inferior's fields of the same name.  */
-    CORE_ADDR l_ld, l_next, l_prev, l_name;
-  };
-
 /* On SVR4 systems, a list of symbols in the dynamic linker where
    GDB can try to place a breakpoint to monitor shared library
    events.
@@ -189,12 +168,12 @@  svr4_same (struct so_list *gdb, struct so_list *inferior)
   return (svr4_same_1 (gdb->so_original_name, inferior->so_original_name));
 }
 
-static struct lm_info *
+static lm_info_svr4 *
 lm_info_read (CORE_ADDR lm_addr)
 {
   struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
   gdb_byte *lm;
-  struct lm_info *lm_info;
+  lm_info_svr4 *lm_info;
   struct cleanup *back_to;
 
   lm = (gdb_byte *) xmalloc (lmo->link_map_size);
@@ -210,7 +189,7 @@  lm_info_read (CORE_ADDR lm_addr)
     {
       struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
 
-      lm_info = XCNEW (struct lm_info);
+      lm_info = XCNEW (lm_info_svr4);
       lm_info->lm_addr = lm_addr;
 
       lm_info->l_addr_inferior = extract_typed_address (&lm[lmo->l_addr_offset],
@@ -240,17 +219,19 @@  has_lm_dynamic_from_link_map (void)
 static CORE_ADDR
 lm_addr_check (const struct so_list *so, bfd *abfd)
 {
-  if (!so->lm_info->l_addr_p)
+  lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+  if (!li->l_addr_p)
     {
       struct bfd_section *dyninfo_sect;
       CORE_ADDR l_addr, l_dynaddr, dynaddr;
 
-      l_addr = so->lm_info->l_addr_inferior;
+      l_addr = li->l_addr_inferior;
 
       if (! abfd || ! has_lm_dynamic_from_link_map ())
 	goto set_addr;
 
-      l_dynaddr = so->lm_info->l_ld;
+      l_dynaddr = li->l_ld;
 
       dyninfo_sect = bfd_get_section_by_name (abfd, ".dynamic");
       if (dyninfo_sect == NULL)
@@ -333,11 +314,11 @@  lm_addr_check (const struct so_list *so, bfd *abfd)
 	}
 
     set_addr:
-      so->lm_info->l_addr = l_addr;
-      so->lm_info->l_addr_p = 1;
+      li->l_addr = l_addr;
+      li->l_addr_p = 1;
     }
 
-  return so->lm_info->l_addr;
+  return li->l_addr;
 }
 
 /* Per pspace SVR4 specific data.  */
@@ -994,9 +975,10 @@  svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
 
   newobj = XCNEW (struct so_list);
   old_chain = make_cleanup (xfree, newobj);
-  newobj->lm_info = lm_info_read (ldsomap);
+  lm_info_svr4 *li = lm_info_read (ldsomap);
+  newobj->lm_info = li;
   make_cleanup (xfree, newobj->lm_info);
-  name_lm = newobj->lm_info ? newobj->lm_info->l_name : 0;
+  name_lm = li != NULL ? li->l_name : 0;
   do_cleanups (old_chain);
 
   return (name_lm >= vaddr && name_lm < vaddr + size);
@@ -1106,8 +1088,10 @@  svr4_free_so (struct so_list *so)
 static void
 svr4_clear_so (struct so_list *so)
 {
-  if (so->lm_info != NULL)
-    so->lm_info->l_addr_p = 0;
+  lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+  if (li != NULL)
+    li->l_addr_p = 0;
 }
 
 /* Free so_list built so far (called via cleanup).  */
@@ -1141,8 +1125,8 @@  svr4_copy_library_list (struct so_list *src)
       newobj = XNEW (struct so_list);
       memcpy (newobj, src, sizeof (struct so_list));
 
-      newobj->lm_info = XNEW (struct lm_info);
-      memcpy (newobj->lm_info, src->lm_info, sizeof (struct lm_info));
+      newobj->lm_info = XNEW (lm_info_svr4);
+      memcpy (newobj->lm_info, src->lm_info, sizeof (lm_info_svr4));
 
       newobj->next = NULL;
       *link = newobj;
@@ -1178,10 +1162,11 @@  library_list_start_library (struct gdb_xml_parser *parser,
   struct so_list *new_elem;
 
   new_elem = XCNEW (struct so_list);
-  new_elem->lm_info = XCNEW (struct lm_info);
-  new_elem->lm_info->lm_addr = *lmp;
-  new_elem->lm_info->l_addr_inferior = *l_addrp;
-  new_elem->lm_info->l_ld = *l_ldp;
+  lm_info_svr4 *li = XCNEW (lm_info_svr4);
+  new_elem->lm_info = li;
+  li->lm_addr = *lmp;
+  li->l_addr_inferior = *l_addrp;
+  li->l_ld = *l_ldp;
 
   strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1);
   new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
@@ -1332,12 +1317,12 @@  svr4_default_sos (void)
     return NULL;
 
   newobj = XCNEW (struct so_list);
-
-  newobj->lm_info = XCNEW (struct lm_info);
+  lm_info_svr4 *li = XCNEW (lm_info_svr4);
+  newobj->lm_info = li;
 
   /* Nothing will ever check the other fields if we set l_addr_p.  */
-  newobj->lm_info->l_addr = info->debug_loader_offset;
-  newobj->lm_info->l_addr_p = 1;
+  li->l_addr = info->debug_loader_offset;
+  li->l_addr_p = 1;
 
   strncpy (newobj->so_name, info->debug_loader_name, SO_NAME_MAX_PATH_SIZE - 1);
   newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
@@ -1371,20 +1356,21 @@  svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
       newobj = XCNEW (struct so_list);
       old_chain = make_cleanup_free_so (newobj);
 
-      newobj->lm_info = lm_info_read (lm);
-      if (newobj->lm_info == NULL)
+      lm_info_svr4 *li = lm_info_read (lm);
+      newobj->lm_info = li;
+      if (li == NULL)
 	{
 	  do_cleanups (old_chain);
 	  return 0;
 	}
 
-      next_lm = newobj->lm_info->l_next;
+      next_lm = li->l_next;
 
-      if (newobj->lm_info->l_prev != prev_lm)
+      if (li->l_prev != prev_lm)
 	{
 	  warning (_("Corrupted shared library list: %s != %s"),
 		   paddress (target_gdbarch (), prev_lm),
-		   paddress (target_gdbarch (), newobj->lm_info->l_prev));
+		   paddress (target_gdbarch (), li->l_prev));
 	  do_cleanups (old_chain);
 	  return 0;
 	}
@@ -1394,26 +1380,26 @@  svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
          SVR4, it has no name.  For others (Solaris 2.3 for example), it
          does have a name, so we can no longer use a missing name to
          decide when to ignore it.  */
-      if (ignore_first && newobj->lm_info->l_prev == 0)
+      if (ignore_first && li->l_prev == 0)
 	{
 	  struct svr4_info *info = get_svr4_info ();
 
-	  first_l_name = newobj->lm_info->l_name;
-	  info->main_lm_addr = newobj->lm_info->lm_addr;
+	  first_l_name = li->l_name;
+	  info->main_lm_addr = li->lm_addr;
 	  do_cleanups (old_chain);
 	  continue;
 	}
 
       /* Extract this shared object's name.  */
-      target_read_string (newobj->lm_info->l_name, &buffer,
-			  SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+      target_read_string (li->l_name, &buffer, SO_NAME_MAX_PATH_SIZE - 1,
+			  &errcode);
       if (errcode != 0)
 	{
 	  /* If this entry's l_name address matches that of the
 	     inferior executable, then this is not a normal shared
 	     object, but (most likely) a vDSO.  In this case, silently
 	     skip it; otherwise emit a warning. */
-	  if (first_l_name == 0 || newobj->lm_info->l_name != first_l_name)
+	  if (first_l_name == 0 || li->l_name != first_l_name)
 	    warning (_("Can't read pathname for load map: %s."),
 		     safe_strerror (errcode));
 	  do_cleanups (old_chain);
@@ -1594,7 +1580,10 @@  svr4_current_sos (void)
 	      [...]
 		[ 9] .dynamic DYNAMIC ffffffffff700580 000580 0000f0
 	  */
-	  if (address_in_mem_range (so->lm_info->l_ld, &vsyscall_range))
+
+	  lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+	  if (address_in_mem_range (li->l_ld, &vsyscall_range))
 	    {
 	      *sop = so->next;
 	      free_so (so);
@@ -1628,7 +1617,11 @@  svr4_fetch_objfile_link_map (struct objfile *objfile)
      of shared libraries.  */
   for (so = master_so_list (); so; so = so->next)
     if (so->objfile == objfile)
-      return so->lm_info->lm_addr;
+      {
+	lm_info_svr4 *li = (lm_info_svr4 *) so->lm_info;
+
+	return li->lm_addr;
+      }
 
   /* Not found!  */
   return 0;
@@ -1860,7 +1853,9 @@  solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
   /* Walk to the end of the list.  */
   for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
     /* Nothing.  */;
-  prev_lm = tail->lm_info->lm_addr;
+
+  lm_info_svr4 *li = (lm_info_svr4 *) tail->lm_info;
+  prev_lm = li->lm_addr;
 
   /* Read the new objects.  */
   if (info->using_xfer)
diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h
index b97fbd62f5..a9b09aa56c 100644
--- a/gdb/solib-svr4.h
+++ b/gdb/solib-svr4.h
@@ -20,11 +20,34 @@ 
 #ifndef SOLIB_SVR4_H
 #define SOLIB_SVR4_H
 
+#include "solist.h"
+
 struct objfile;
 struct target_so_ops;
 
 extern struct target_so_ops svr4_so_ops;
 
+/* Link map info to include in an allocated so_list entry.  */
+
+struct lm_info_svr4 : public lm_info_base
+{
+  /* Amount by which addresses in the binary should be relocated to
+     match the inferior.  The direct inferior value is L_ADDR_INFERIOR.
+     When prelinking is involved and the prelink base address changes,
+     we may need a different offset - the recomputed offset is in L_ADDR.
+     It is commonly the same value.  It is cached as we want to warn about
+     the difference and compute it only once.  L_ADDR is valid
+     iff L_ADDR_P.  */
+  CORE_ADDR l_addr, l_addr_inferior;
+  unsigned int l_addr_p : 1;
+
+  /* The target location of lm.  */
+  CORE_ADDR lm_addr;
+
+  /* Values read in from inferior's fields of the same name.  */
+  CORE_ADDR l_ld, l_next, l_prev, l_name;
+};
+
 /* Critical offsets and sizes which describe struct r_debug and
    struct link_map on SVR4-like targets.  All offsets and sizes are
    in bytes unless otherwise specified.  */
diff --git a/gdb/solib-target.c b/gdb/solib-target.c
index 1b10e4ea41..e40acc1823 100644
--- a/gdb/solib-target.c
+++ b/gdb/solib-target.c
@@ -27,7 +27,7 @@ 
 #include "solib-target.h"
 
 /* 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.  */
@@ -49,12 +49,12 @@  struct lm_info
   struct section_offsets *offsets;
 };
 
-typedef struct lm_info *lm_info_p;
-DEF_VEC_P(lm_info_p);
+typedef lm_info_target *lm_info_target_p;
+DEF_VEC_P(lm_info_target_p);
 
 #if !defined(HAVE_LIBEXPAT)
 
-static VEC(lm_info_p) *
+static VEC(lm_info_target_p) *
 solib_target_parse_libraries (const char *library)
 {
   static int have_warned;
@@ -80,8 +80,8 @@  library_list_start_segment (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 = (VEC(lm_info_p) **) user_data;
-  struct lm_info *last = VEC_last (lm_info_p, *list);
+  VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+  lm_info_target *last = VEC_last (lm_info_target_p, *list);
   ULONGEST *address_p
     = (ULONGEST *) xml_find_attribute (attributes, "address")->value;
   CORE_ADDR address = (CORE_ADDR) *address_p;
@@ -98,8 +98,8 @@  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 = (VEC(lm_info_p) **) user_data;
-  struct lm_info *last = VEC_last (lm_info_p, *list);
+  VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+  lm_info_target *last = VEC_last (lm_info_target_p, *list);
   ULONGEST *address_p
     = (ULONGEST *) xml_find_attribute (attributes, "address")->value;
   CORE_ADDR address = (CORE_ADDR) *address_p;
@@ -118,13 +118,13 @@  library_list_start_library (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 = (VEC(lm_info_p) **) user_data;
-  struct lm_info *item = XCNEW (struct lm_info);
+  VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+  lm_info_target *item = XCNEW (lm_info_target);
   const char *name
     = (const char *) xml_find_attribute (attributes, "name")->value;
 
   item->name = xstrdup (name);
-  VEC_safe_push (lm_info_p, *list, item);
+  VEC_safe_push (lm_info_target_p, *list, item);
 }
 
 static void
@@ -132,8 +132,8 @@  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 = (VEC(lm_info_p) **) user_data;
-  struct lm_info *lm_info = VEC_last (lm_info_p, *list);
+  VEC(lm_info_target_p) **list = (VEC(lm_info_target_p) **) user_data;
+  lm_info_target *lm_info = VEC_last (lm_info_target_p, *list);
 
   if (lm_info->segment_bases == NULL
       && lm_info->section_bases == NULL)
@@ -168,18 +168,18 @@  library_list_start_list (struct gdb_xml_parser *parser,
 static void
 solib_target_free_library_list (void *p)
 {
-  VEC(lm_info_p) **result = (VEC(lm_info_p) **) p;
-  struct lm_info *info;
+  VEC(lm_info_target_p) **result = (VEC(lm_info_target_p) **) p;
+  lm_info_target *info;
   int ix;
 
-  for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++)
+  for (ix = 0; VEC_iterate (lm_info_target_p, *result, ix, info); ix++)
     {
       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);
+  VEC_free (lm_info_target_p, *result);
   *result = NULL;
 }
 
@@ -229,10 +229,10 @@  static const struct gdb_xml_element library_list_elements[] = {
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
-static VEC(lm_info_p) *
+static VEC(lm_info_target_p) *
 solib_target_parse_libraries (const char *library)
 {
-  VEC(lm_info_p) *result = NULL;
+  VEC(lm_info_target_p) *result = NULL;
   struct cleanup *back_to = make_cleanup (solib_target_free_library_list,
 					  &result);
 
@@ -255,8 +255,8 @@  solib_target_current_sos (void)
   struct so_list *new_solib, *start = NULL, *last = NULL;
   char *library_document;
   struct cleanup *old_chain;
-  VEC(lm_info_p) *library_list;
-  struct lm_info *info;
+  VEC(lm_info_target_p) *library_list;
+  lm_info_target *info;
   int ix;
 
   /* Fetch the list of shared libraries.  */
@@ -279,7 +279,7 @@  solib_target_current_sos (void)
     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 (ix = 0; VEC_iterate (lm_info_target_p, library_list, ix, info); ix++)
     {
       new_solib = XCNEW (struct so_list);
       strncpy (new_solib->so_name, info->name, SO_NAME_MAX_PATH_SIZE - 1);
@@ -304,7 +304,7 @@  solib_target_current_sos (void)
     }
 
   /* Free the library list, but not its members.  */
-  VEC_free (lm_info_p, library_list);
+  VEC_free (lm_info_target_p, library_list);
 
   return start;
 }
@@ -324,10 +324,12 @@  solib_target_clear_solib (void)
 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 == NULL);
+  xfree (li->offsets);
+  VEC_free (CORE_ADDR, li->segment_bases);
+  xfree (li);
 }
 
 static void
@@ -335,23 +337,24 @@  solib_target_relocate_section_addresses (struct so_list *so,
 					 struct target_section *sec)
 {
   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)
     {
       int num_sections = gdb_bfd_count_sections (so->abfd);
 
-      so->lm_info->offsets
+      li->offsets
 	= ((struct section_offsets *)
 	   xzalloc (SIZEOF_N_SECTION_OFFSETS (num_sections)));
 
-      if (so->lm_info->section_bases)
+      if (li->section_bases)
 	{
 	  int i;
 	  asection *sect;
 	  int num_section_bases
-	    = VEC_length (CORE_ADDR, so->lm_info->section_bases);
+	    = VEC_length (CORE_ADDR, li->section_bases);
 	  int num_alloc_sections = 0;
 
 	  for (i = 0, sect = so->abfd->sections;
@@ -371,7 +374,7 @@  Could not relocate shared library \"%s\": wrong number of ALLOC sections"),
 	      CORE_ADDR *section_bases;
 
 	      section_bases = VEC_address (CORE_ADDR,
-					   so->lm_info->section_bases);
+					   li->section_bases);
 
 	      so->addr_low = ~(CORE_ADDR) 0;
 	      so->addr_high = 0;
@@ -395,7 +398,7 @@  Could not relocate shared library \"%s\": wrong number of ALLOC sections"),
 		      gdb_assert (so->addr_low <= so->addr_high);
 		      found_range = 1;
 		    }
-		  so->lm_info->offsets->offsets[i]
+		  li->offsets->offsets[i]
 		    = section_bases[bases_index];
 		  bases_index++;
 		}
@@ -404,7 +407,7 @@  Could not relocate shared library \"%s\": wrong number of ALLOC sections"),
 	      gdb_assert (so->addr_low <= so->addr_high);
 	    }
 	}
-      else if (so->lm_info->segment_bases)
+      else if (li->segment_bases)
 	{
 	  struct symfile_segment_data *data;
 
@@ -419,12 +422,10 @@  Could not relocate shared library \"%s\": no segments"), so->so_name);
 	      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);
+	      num_bases = VEC_length (CORE_ADDR, li->segment_bases);
+	      segment_bases = VEC_address (CORE_ADDR, li->segment_bases);
 
-	      if (!symfile_map_offsets_to_segments (so->abfd, data,
-						    so->lm_info->offsets,
+	      if (!symfile_map_offsets_to_segments (so->abfd, data, li->offsets,
 						    num_bases, segment_bases))
 		warning (_("\
 Could not relocate shared library \"%s\": bad offsets"), so->so_name);
@@ -459,9 +460,9 @@  Could not relocate shared library \"%s\": bad offsets"), so->so_name);
 	}
     }
 
-  offset = so->lm_info->offsets->offsets[gdb_bfd_section_index
-					 (sec->the_bfd_section->owner,
-					  sec->the_bfd_section)];
+  offset = li->offsets->offsets[gdb_bfd_section_index
+			        (sec->the_bfd_section->owner,
+				 sec->the_bfd_section)];
   sec->addr += offset;
   sec->endaddr += offset;
 }
diff --git a/gdb/solist.h b/gdb/solist.h
index 378d60d7b8..54c9902b4a 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -29,9 +29,11 @@ 
 	 so != NULL; \
 	 so = so->next)
 
-/* Forward declaration for target specific link map information.  This
-   struct is opaque to all but the target specific file.  */
-struct lm_info;
+/* Base class for target-specific link map information.  */
+
+struct lm_info_base
+{
+};
 
 struct so_list
   {
@@ -45,7 +47,7 @@  struct so_list
        will be a copy of struct link_map from the user process, but
        it need not be; it can be any collection of data needed to
        traverse the dynamic linker's data structures.  */
-    struct lm_info *lm_info;
+    lm_info_base *lm_info;
 
     /* Shared object file name, exactly as it appears in the
        inferior's link map.  This may be a relative path, or something
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 805fb4358d..ef1c2914f1 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -585,7 +585,7 @@  struct safe_symbol_file_add_args
 };
 
 /* Maintain a linked list of "so" information.  */
-struct lm_info
+struct lm_info_windows : public lm_info_base
 {
   LPVOID load_addr;
 };
@@ -645,8 +645,9 @@  windows_make_so (const char *name, LPVOID load_addr)
     }
 #endif
   so = XCNEW (struct so_list);
-  so->lm_info = XNEW (struct lm_info);
-  so->lm_info->load_addr = load_addr;
+  lm_info_windows *li = XCNEW (struct lm_info_windows);
+  so->lm_info = li;
+  li->load_addr = load_addr;
   strcpy (so->so_original_name, name);
 #ifndef __CYGWIN__
   strcpy (so->so_name, buf);
@@ -772,8 +773,10 @@  handle_load_dll (void *dummy)
   solib_end->next = windows_make_so (dll_name, event->lpBaseOfDll);
   solib_end = solib_end->next;
 
+  lm_info_windows *li = (lm_info_windows *) solib_end->lm_info;
+
   DEBUG_EVENTS (("gdb: Loading dll \"%s\" at %s.\n", solib_end->so_name,
-		 host_address_to_string (solib_end->lm_info->load_addr)));
+		 host_address_to_string (li->load_addr)));
 
   return 1;
 }
@@ -801,18 +804,22 @@  handle_unload_dll (void *dummy)
   struct so_list *so;
 
   for (so = &solib_start; so->next != NULL; so = so->next)
-    if (so->next->lm_info->load_addr == lpBaseOfDll)
-      {
-	struct so_list *sodel = so->next;
+    {
+      lm_info_windows *li_next = (lm_info_windows *) so->next->lm_info;
 
-	so->next = sodel->next;
-	if (!so->next)
-	  solib_end = so;
-	DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+      if (li_next->load_addr == lpBaseOfDll)
+	{
+	  struct so_list *sodel = so->next;
 
-	windows_free_so (sodel);
-	return 1;
-      }
+	  so->next = sodel->next;
+	  if (!so->next)
+	    solib_end = so;
+	  DEBUG_EVENTS (("gdb: Unloading dll \"%s\".\n", sodel->so_name));
+
+	  windows_free_so (sodel);
+	  return 1;
+	}
+    }
 
   /* We did not find any DLL that was previously loaded at this address,
      so register a complaint.  We do not report an error, because we have
@@ -2842,9 +2849,13 @@  windows_xfer_shared_libraries (struct target_ops *ops,
   obstack_init (&obstack);
   obstack_grow_str (&obstack, "<library-list>\n");
   for (so = solib_start.next; so; so = so->next)
-    windows_xfer_shared_library (so->so_name, (CORE_ADDR)
-				 (uintptr_t) so->lm_info->load_addr,
-				 target_gdbarch (), &obstack);
+    {
+      lm_info_windows *li = (lm_info_windows *) so->lm_info;
+
+      windows_xfer_shared_library (so->so_name, (CORE_ADDR)
+				   (uintptr_t) li->load_addr,
+				   target_gdbarch (), &obstack);
+    }
   obstack_grow_str0 (&obstack, "</library-list>\n");
 
   buf = (const char *) obstack_finish (&obstack);