This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Add shared library support for FR-V FDPIC ABI


I've just committed the patch below.

As noted in the subject line, it adds shared library support for the
FR-V FDPIC ABI.  For those that are curious, the reason that
solib-svr4.c could not be used is due to the fact that the FDPIC ABI
allows relocation of text and data segments by different amounts.

	Add shared library support for FR-V FDPIC ABI:
	* Makefile.in (solib-frv.o): Add dependencies.
	* frv-tdep.c (find_func_descr, frv_convert_from_func_ptr_addr):
	New functions.
	(frv_push_dummy_call): Add support for FDPIC ABI.
	(frv_gdbarch_init): Call set_gdbarch_convert_from_func_ptr_addr()
	for FDPIC ABI.
	* frv-tdep.h (frv_fdpic_find_global_pointer): Declare.
	(frv_fdpic_find_canonical_descriptor): Declare.
	* solib-frv.c: New file.
	* config/frv/frv.mt (TDEPFILES): Add solib.o and solib-frv.o.
	* config/frv/tm-frv.h (solib.h): Include.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.520
diff -u -p -r1.520 Makefile.in
--- Makefile.in	13 Mar 2004 00:36:53 -0000	1.520
+++ Makefile.in	13 Mar 2004 00:39:57 -0000
@@ -2298,6 +2298,9 @@ solib.o: solib.c $(defs_h) $(gdb_string_
 	$(objfiles_h) $(gdbcore_h) $(command_h) $(target_h) $(frame_h) \
 	$(gdb_regex_h) $(inferior_h) $(environ_h) $(language_h) $(gdbcmd_h) \
 	$(completer_h) $(filenames_h) $(exec_h) $(solist_h) $(readline_h)
+solib-frv.o: solib-frv.c $(defs_h) $(gdb_string_h) $(inferior_h) $(gdbcore_h) \
+	$(solist_h) $(frv_tdep_h) $(objfiles_h) $(symtab_h) $(language_h) \
+	$(command_h) $(gdbcmd_h) $(elf_frv_h)
 solib-irix.o: solib-irix.c $(defs_h) $(symtab_h) $(bfd_h) $(symfile_h) \
 	$(objfiles_h) $(gdbcore_h) $(target_h) $(inferior_h) $(solist_h)
 solib-legacy.o: solib-legacy.c $(defs_h) $(gdbcore_h) $(solib_svr4_h)
Index: frv-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/frv-tdep.c,v
retrieving revision 1.73
diff -u -p -r1.73 frv-tdep.c
--- frv-tdep.c	13 Mar 2004 00:16:23 -0000	1.73
+++ frv-tdep.c	13 Mar 2004 00:39:58 -0000
@@ -1037,6 +1037,45 @@ frv_frame_align (struct gdbarch *gdbarch
 }
 
 static CORE_ADDR
+find_func_descr (struct gdbarch *gdbarch, CORE_ADDR entry_point)
+{
+  CORE_ADDR descr;
+  char valbuf[4];
+
+  descr = frv_fdpic_find_canonical_descriptor (entry_point);
+
+  if (descr != 0)
+    return descr;
+
+  /* Construct a non-canonical descriptor from space allocated on
+     the stack.  */
+
+  descr = value_as_long (value_allocate_space_in_inferior (8));
+  store_unsigned_integer (valbuf, 4, entry_point);
+  write_memory (descr, valbuf, 4);
+  store_unsigned_integer (valbuf, 4,
+                          frv_fdpic_find_global_pointer (entry_point));
+  write_memory (descr + 4, valbuf, 4);
+  return descr;
+}
+
+static CORE_ADDR
+frv_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr,
+                                struct target_ops *targ)
+{
+  CORE_ADDR entry_point;
+  CORE_ADDR got_address;
+
+  entry_point = get_target_memory_unsigned (targ, addr, 4);
+  got_address = get_target_memory_unsigned (targ, addr + 4, 4);
+
+  if (got_address == frv_fdpic_find_global_pointer (entry_point))
+    return entry_point;
+  else
+    return addr;
+}
+
+static CORE_ADDR
 frv_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
                      struct regcache *regcache, CORE_ADDR bp_addr,
                      int nargs, struct value **args, CORE_ADDR sp,
@@ -1053,6 +1092,7 @@ frv_push_dummy_call (struct gdbarch *gdb
   CORE_ADDR regval;
   int stack_space;
   int stack_offset;
+  enum frv_abi abi = frv_abi (gdbarch);
 
 #if 0
   printf("Push %d args at sp = %x, struct_return=%d (%x)\n",
@@ -1092,6 +1132,22 @@ frv_push_dummy_call (struct gdbarch *gdb
 	  len = 4;
 	  val = valbuf;
 	}
+      else if (abi == FRV_ABI_FDPIC
+	       && len == 4
+               && typecode == TYPE_CODE_PTR
+               && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC)
+	{
+	  /* The FDPIC ABI requires function descriptors to be passed instead
+	     of entry points.  */
+	  store_unsigned_integer
+	    (valbuf, 4,
+	     find_func_descr (gdbarch,
+	                      extract_unsigned_integer (VALUE_CONTENTS (arg),
+			                                4)));
+	  typecode = TYPE_CODE_PTR;
+	  len = 4;
+	  val = valbuf;
+	}
       else
 	{
 	  val = (char *) VALUE_CONTENTS (arg);
@@ -1129,6 +1185,14 @@ frv_push_dummy_call (struct gdbarch *gdb
      always at BP_ADDR.  */
   regcache_cooked_write_unsigned (regcache, lr_regnum, bp_addr);
 
+  if (abi == FRV_ABI_FDPIC)
+    {
+      /* Set the GOT register for the FDPIC ABI.  */
+      regcache_cooked_write_unsigned
+	(regcache, first_gpr_regnum + 15,
+         frv_fdpic_find_global_pointer (func_addr));
+    }
+
   /* Finally, update the SP register.  */
   regcache_cooked_write_unsigned (regcache, sp_regnum, sp);
 
@@ -1449,6 +1513,9 @@ frv_gdbarch_init (struct gdbarch_info in
     }
 
   set_gdbarch_print_insn (gdbarch, print_insn_frv);
+  if (frv_abi (gdbarch) == FRV_ABI_FDPIC)
+    set_gdbarch_convert_from_func_ptr_addr (gdbarch,
+					    frv_convert_from_func_ptr_addr);
 
   return gdbarch;
 }
Index: frv-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/frv-tdep.h,v
retrieving revision 1.1
diff -u -p -r1.1 frv-tdep.h
--- frv-tdep.h	13 Mar 2004 00:16:23 -0000	1.1
+++ frv-tdep.h	13 Mar 2004 00:39:58 -0000
@@ -33,3 +33,12 @@ enum frv_abi frv_abi (struct gdbarch *gd
    not.  (E.g, -1 will be returned if the ABI isn't the FDPIC ABI.)  */
 int frv_fdpic_loadmap_addresses (struct gdbarch *gdbarch,
                                  CORE_ADDR *interp_addr, CORE_ADDR *exec_addr);
+
+/* Given a function entry point, find and return the GOT address for the
+   containing load module.  */
+CORE_ADDR frv_fdpic_find_global_pointer (CORE_ADDR addr);
+
+/* Given a function entry point, find and return the canonical descriptor
+   for that function, if one exists.  If no canonical descriptor could
+   be found, return 0.  */
+CORE_ADDR frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point);
Index: solib-frv.c
===================================================================
RCS file: solib-frv.c
diff -N solib-frv.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ solib-frv.c	13 Mar 2004 00:39:58 -0000
@@ -0,0 +1,1230 @@
+/* Handle FR-V (FDPIC) shared libraries for GDB, the GNU Debugger.
+   Copyright 2004
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "solist.h"
+#include "frv-tdep.h"
+#include "objfiles.h"
+#include "symtab.h"
+#include "language.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "elf/frv.h"
+
+/* Flag which indicates whether internal debug messages should be printed.  */
+static int solib_frv_debug;
+
+/* FR-V pointers are four bytes wide.  */
+enum { FRV_PTR_SIZE = 4 };
+
+/* Representation of loadmap and related structs for the FR-V FDPIC ABI.  */
+
+/* External versions; the size and alignment of the fields should be
+   the same as those on the target.  When loaded, the placement of
+   the bits in each field will be the same as on the target.  */
+typedef unsigned char ext_Elf32_Half[2];
+typedef unsigned char ext_Elf32_Addr[4];
+typedef unsigned char ext_Elf32_Word[4];
+
+struct ext_elf32_fdpic_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  ext_Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  ext_Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  ext_Elf32_Word p_memsz;
+};
+
+struct ext_elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  ext_Elf32_Half version;
+  /* Number of segments in this map.  */
+  ext_Elf32_Half nsegs;
+  /* The actual memory map.  */
+  struct ext_elf32_fdpic_loadseg segs[1 /* nsegs, actually */];
+};
+
+/* Internal versions; the types are GDB types and the data in each
+   of the fields is (or will be) decoded from the external struct
+   for ease of consumption.  */
+struct int_elf32_fdpic_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  CORE_ADDR addr;
+  /* VMA recorded in the program header.  */
+  CORE_ADDR p_vaddr;
+  /* Size of this segment in memory.  */
+  long p_memsz;
+};
+
+struct int_elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  int version;
+  /* Number of segments in this map.  */
+  int nsegs;
+  /* The actual memory map.  */
+  struct int_elf32_fdpic_loadseg segs[1 /* nsegs, actually */];
+};
+
+/* Given address LDMADDR, fetch and decode the loadmap at that address.
+   Return NULL if there is a problem reading the target memory or if
+   there doesn't appear to be a loadmap at the given address.  The
+   allocated space (representing the loadmap) returned by this
+   function may be freed via a single call to xfree().  */
+
+static struct int_elf32_fdpic_loadmap *
+fetch_loadmap (CORE_ADDR ldmaddr)
+{
+  struct ext_elf32_fdpic_loadmap ext_ldmbuf_partial;
+  struct ext_elf32_fdpic_loadmap *ext_ldmbuf;
+  struct int_elf32_fdpic_loadmap *int_ldmbuf;
+  int ext_ldmbuf_size, int_ldmbuf_size;
+  int version, seg, nsegs;
+
+  /* Fetch initial portion of the loadmap.  */
+  if (target_read_memory (ldmaddr, (char *) &ext_ldmbuf_partial,
+                          sizeof ext_ldmbuf_partial))
+    {
+      /* Problem reading the target's memory.  */
+      return NULL;
+    }
+
+  /* Extract the version.  */
+  version = extract_unsigned_integer (&ext_ldmbuf_partial.version,
+                                      sizeof ext_ldmbuf_partial.version);
+  if (version != 0)
+    {
+      /* We only handle version 0.  */
+      return NULL;
+    }
+
+  /* Extract the number of segments.  */
+  nsegs = extract_unsigned_integer (&ext_ldmbuf_partial.nsegs,
+                                    sizeof ext_ldmbuf_partial.nsegs);
+
+  /* Allocate space for the complete (external) loadmap.  */
+  ext_ldmbuf_size = sizeof (struct ext_elf32_fdpic_loadmap)
+               + (nsegs - 1) * sizeof (struct ext_elf32_fdpic_loadseg);
+  ext_ldmbuf = xmalloc (ext_ldmbuf_size);
+
+  /* Copy over the portion of the loadmap that's already been read.  */
+  memcpy (ext_ldmbuf, &ext_ldmbuf_partial, sizeof ext_ldmbuf_partial);
+
+  /* Read the rest of the loadmap from the target.  */
+  if (target_read_memory (ldmaddr + sizeof ext_ldmbuf_partial,
+                          (char *) ext_ldmbuf + sizeof ext_ldmbuf_partial,
+                          ext_ldmbuf_size - sizeof ext_ldmbuf_partial))
+    {
+      /* Couldn't read rest of the loadmap.  */
+      xfree (ext_ldmbuf);
+      return NULL;
+    }
+
+  /* Allocate space into which to put information extract from the
+     external loadsegs.  I.e, allocate the internal loadsegs.  */
+  int_ldmbuf_size = sizeof (struct int_elf32_fdpic_loadmap)
+               + (nsegs - 1) * sizeof (struct int_elf32_fdpic_loadseg);
+  int_ldmbuf = xmalloc (int_ldmbuf_size);
+
+  /* Place extracted information in internal structs.  */
+  int_ldmbuf->version = version;
+  int_ldmbuf->nsegs = nsegs;
+  for (seg = 0; seg < nsegs; seg++)
+    {
+      int_ldmbuf->segs[seg].addr
+	= extract_unsigned_integer (&ext_ldmbuf->segs[seg].addr,
+	                            sizeof (ext_ldmbuf->segs[seg].addr));
+      int_ldmbuf->segs[seg].p_vaddr
+	= extract_unsigned_integer (&ext_ldmbuf->segs[seg].p_vaddr,
+	                            sizeof (ext_ldmbuf->segs[seg].p_vaddr));
+      int_ldmbuf->segs[seg].p_memsz
+	= extract_unsigned_integer (&ext_ldmbuf->segs[seg].p_memsz,
+	                            sizeof (ext_ldmbuf->segs[seg].p_memsz));
+    }
+
+  free (ext_ldmbuf);
+  return int_ldmbuf;
+}
+
+/* External link_map and elf32_fdpic_loadaddr struct definitions.  */
+
+typedef unsigned char ext_ptr[4];
+
+struct ext_elf32_fdpic_loadaddr
+{
+  ext_ptr map;			/* struct elf32_fdpic_loadmap *map; */
+  ext_ptr got_value;		/* void *got_value; */
+};
+
+struct ext_link_map
+{
+  struct ext_elf32_fdpic_loadaddr l_addr;
+
+  /* Absolute file name object was found in.  */
+  ext_ptr l_name;		/* char *l_name; */
+
+  /* Dynamic section of the shared object.  */
+  ext_ptr l_ld;			/* ElfW(Dyn) *l_ld; */
+
+  /* Chain of loaded objects.  */
+  ext_ptr l_next, l_prev;	/* struct link_map *l_next, *l_prev; */
+};
+
+/* Link map info to include in an allocated so_list entry */
+
+struct lm_info
+  {
+    /* The loadmap, digested into an easier to use form.  */
+    struct int_elf32_fdpic_loadmap *map;
+    /* The GOT address for this link map entry.  */
+    CORE_ADDR got_value;
+
+    /* Cached dynamic symbol table and dynamic relocs initialized and
+       used only by find_canonical_descriptor_in_load_object().
+
+       Note: kevinb/2004-02-26: It appears that calls to
+       bfd_canonicalize_dynamic_reloc() will use the same symbols as
+       those supplied to the first call to this function.  Therefore,
+       it's important to NOT free the asymbol ** data structure
+       supplied to the first call.  Thus the caching of the dynamic
+       symbols (dyn_syms) is critical for correct operation.  The
+       caching of the dynamic relocations could be dispensed with.  */
+    asymbol **dyn_syms;
+    arelent **dyn_relocs;
+    int dyn_reloc_count;	/* number of dynamic relocs.  */
+
+  };
+
+/* The load map, got value, etc. are not available from the chain
+   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 void frv_relocate_main_executable (void);
+static CORE_ADDR main_got (void);
+static int enable_break2 (void);
+
+/*
+
+   LOCAL FUNCTION
+
+   bfd_lookup_symbol -- lookup the value for a specific symbol
+
+   SYNOPSIS
+
+   CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname)
+
+   DESCRIPTION
+
+   An expensive way to lookup the value of a single symbol for
+   bfd's that are only temporary anyway.  This is used by the
+   shared library support to find the address of the debugger
+   interface structures in the shared library.
+
+   Note that 0 is specifically allowed as an error return (no
+   such symbol).
+ */
+
+static CORE_ADDR
+bfd_lookup_symbol (bfd *abfd, char *symname)
+{
+  long storage_needed;
+  asymbol *sym;
+  asymbol **symbol_table;
+  unsigned int number_of_symbols;
+  unsigned int i;
+  struct cleanup *back_to;
+  CORE_ADDR symaddr = 0;
+
+  storage_needed = bfd_get_symtab_upper_bound (abfd);
+
+  if (storage_needed > 0)
+    {
+      symbol_table = (asymbol **) xmalloc (storage_needed);
+      back_to = make_cleanup (xfree, symbol_table);
+      number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+      for (i = 0; i < number_of_symbols; i++)
+	{
+	  sym = *symbol_table++;
+	  if (strcmp (sym->name, symname) == 0)
+	    {
+	      /* Bfd symbols are section relative. */
+	      symaddr = sym->value + sym->section->vma;
+	      break;
+	    }
+	}
+      do_cleanups (back_to);
+    }
+
+  if (symaddr)
+    return symaddr;
+
+  /* Look for the symbol in the dynamic string table too.  */
+
+  storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+
+  if (storage_needed > 0)
+    {
+      symbol_table = (asymbol **) xmalloc (storage_needed);
+      back_to = make_cleanup (xfree, symbol_table);
+      number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
+
+      for (i = 0; i < number_of_symbols; i++)
+	{
+	  sym = *symbol_table++;
+	  if (strcmp (sym->name, symname) == 0)
+	    {
+	      /* Bfd symbols are section relative. */
+	      symaddr = sym->value + sym->section->vma;
+	      break;
+	    }
+	}
+      do_cleanups (back_to);
+    }
+
+  return symaddr;
+}
+
+
+/*
+
+  LOCAL FUNCTION
+
+  open_symbol_file_object
+
+  SYNOPSIS
+
+  void open_symbol_file_object (void *from_tty)
+
+  DESCRIPTION
+
+  If no open symbol file, attempt to locate and open the main symbol
+  file.
+
+  If FROM_TTYP dereferences to a non-zero integer, allow messages to
+  be printed.  This parameter is a pointer rather than an int because
+  open_symbol_file_object() is called via catch_errors() and
+  catch_errors() requires a pointer argument. */
+
+static int
+open_symbol_file_object (void *from_ttyp)
+{
+  /* Unimplemented.  */
+  return 0;
+}
+
+/* Cached value for lm_base(), below.  */
+static CORE_ADDR lm_base_cache = 0;
+
+/* Return the address from which the link map chain may be found.  On
+   the FR-V, this may be found in a number of ways.  Assuming that the
+   main executable has already been relocated, the easiest way to find
+   this value is to look up the address of _GLOBAL_OFFSET_TABLE_.  A
+   pointer to the start of the link map will be located at the word found
+   at _GLOBAL_OFFSET_TABLE_ + 8.  (This is part of the dynamic linker
+   reserve area mandated by the ABI.)  */
+
+static CORE_ADDR
+lm_base (void)
+{
+  struct minimal_symbol *got_sym;
+  CORE_ADDR addr;
+  char buf[FRV_PTR_SIZE];
+
+  /* If we already have a cached value, return it.  */
+  if (lm_base_cache)
+    return lm_base_cache;
+
+  got_sym = lookup_minimal_symbol ("_GLOBAL_OFFSET_TABLE_", NULL,
+                                   symfile_objfile);
+  if (got_sym == 0)
+    {
+      if (solib_frv_debug)
+	fprintf_unfiltered (gdb_stdlog,
+	                    "lm_base: _GLOBAL_OFFSET_TABLE_ not found.\n");
+      return 0;
+    }
+
+  addr = SYMBOL_VALUE_ADDRESS (got_sym) + 8;
+
+  if (solib_frv_debug)
+    fprintf_unfiltered (gdb_stdlog,
+			"lm_base: _GLOBAL_OFFSET_TABLE_ + 8 = %s\n",
+			local_hex_string_custom (addr, "08l"));
+
+  if (target_read_memory (addr, buf, sizeof buf) != 0)
+    return 0;
+  lm_base_cache = extract_unsigned_integer (buf, sizeof buf);
+
+  if (solib_frv_debug)
+    fprintf_unfiltered (gdb_stdlog,
+			"lm_base: lm_base_cache = %s\n",
+			local_hex_string_custom (lm_base_cache, "08l"));
+
+  return lm_base_cache;
+}
+
+
+/* LOCAL FUNCTION
+
+   frv_current_sos -- build a list of currently loaded shared objects
+
+   SYNOPSIS
+
+   struct so_list *frv_current_sos ()
+
+   DESCRIPTION
+
+   Build a list of `struct so_list' objects describing the shared
+   objects currently loaded in the inferior.  This list does not
+   include an entry for the main executable file.
+
+   Note that we only gather information directly available from the
+   inferior --- we don't examine any of the shared library files
+   themselves.  The declaration of `struct so_list' says which fields
+   we provide values for.  */
+
+static struct so_list *
+frv_current_sos (void)
+{
+  CORE_ADDR lm_addr, mgot;
+  struct so_list *sos_head = NULL;
+  struct so_list **sos_next_ptr = &sos_head;
+
+  mgot = main_got ();
+
+  /* Locate the address of the first link map struct.  */
+  lm_addr = lm_base ();
+
+  /* We have at least one link map entry.  Fetch the the lot of them,
+     building the solist chain.  */
+  while (lm_addr)
+    {
+      struct ext_link_map lm_buf;
+      CORE_ADDR got_addr;
+
+      if (solib_frv_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "current_sos: reading link_map entry at %s\n",
+			    local_hex_string_custom (lm_addr, "08l"));
+
+      if (target_read_memory (lm_addr, (char *) &lm_buf, sizeof (lm_buf)) != 0)
+	{
+	  warning ("frv_current_sos: Unable to read link map entry.  Shared object chain may be incomplete.");
+	  break;
+	}
+
+      got_addr
+	= extract_unsigned_integer (&lm_buf.l_addr.got_value,
+				    sizeof (lm_buf.l_addr.got_value));
+      /* If the got_addr is the same as mgotr, then we're looking at the
+	 entry for the main executable.  By convention, we don't include
+	 this in the list of shared objects.  */
+      if (got_addr != mgot)
+	{
+	  int errcode;
+	  char *name_buf;
+	  struct int_elf32_fdpic_loadmap *loadmap;
+	  struct so_list *sop;
+	  CORE_ADDR addr;
+
+	  /* Fetch the load map address.  */
+	  addr = extract_unsigned_integer (&lm_buf.l_addr.map,
+					   sizeof lm_buf.l_addr.map);
+	  loadmap = fetch_loadmap (addr);
+	  if (loadmap == NULL)
+	    {
+	      warning ("frv_current_sos: Unable to fetch load map.  Shared object chain may be incomplete.");
+	      break;
+	    }
+
+	  sop = xcalloc (1, sizeof (struct so_list));
+	  sop->lm_info = xcalloc (1, sizeof (struct lm_info));
+	  sop->lm_info->map = loadmap;
+	  sop->lm_info->got_value = got_addr;
+	  /* Fetch the name.  */
+	  addr = extract_unsigned_integer (&lm_buf.l_name,
+					   sizeof (lm_buf.l_name));
+	  target_read_string (addr, &name_buf, SO_NAME_MAX_PATH_SIZE - 1,
+			      &errcode);
+
+	  if (solib_frv_debug)
+	    fprintf_unfiltered (gdb_stdlog, "current_sos: name = %s\n",
+	                        name_buf);
+	  
+	  if (errcode != 0)
+	    {
+	      warning ("frv_current_sos: Can't read pathname for link map entry: %s\n",
+		       safe_strerror (errcode));
+	    }
+	  else
+	    {
+	      strncpy (sop->so_name, name_buf, SO_NAME_MAX_PATH_SIZE - 1);
+	      sop->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+	      xfree (name_buf);
+	      strcpy (sop->so_original_name, sop->so_name);
+	    }
+
+	  *sos_next_ptr = sop;
+	  sos_next_ptr = &sop->next;
+	}
+
+      lm_addr = extract_unsigned_integer (&lm_buf.l_next, sizeof (lm_buf.l_next));
+    }
+
+  enable_break2 ();
+
+  return sos_head;
+}
+
+
+/* Return 1 if PC lies in the dynamic symbol resolution code of the
+   run time loader.  */
+
+static CORE_ADDR interp_text_sect_low;
+static CORE_ADDR interp_text_sect_high;
+static CORE_ADDR interp_plt_sect_low;
+static CORE_ADDR interp_plt_sect_high;
+
+static int
+frv_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
+	  || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
+	  || in_plt_section (pc, NULL));
+}
+
+/* Given a loadmap and an address, return the displacement needed
+   to relocate the address.  */
+
+CORE_ADDR
+displacement_from_map (struct int_elf32_fdpic_loadmap *map,
+                       CORE_ADDR addr)
+{
+  int seg;
+
+  for (seg = 0; seg < map->nsegs; seg++)
+    {
+      if (map->segs[seg].p_vaddr <= addr
+          && addr < map->segs[seg].p_vaddr + map->segs[seg].p_memsz)
+	{
+	  return map->segs[seg].addr - map->segs[seg].p_vaddr;
+	}
+    }
+
+  return 0;
+}
+
+/* Print a warning about being unable to set the dynamic linker
+   breakpoint.  */
+
+static void
+enable_break_failure_warning (void)
+{
+  warning ("Unable to find dynamic linker breakpoint function.\n"
+           "GDB will be unable to debug shared library initializers\n"
+	   "and track explicitly loaded dynamic code.");
+}
+
+/*
+
+   LOCAL FUNCTION
+
+   enable_break -- arrange for dynamic linker to hit breakpoint
+
+   SYNOPSIS
+
+   int enable_break (void)
+
+   DESCRIPTION
+
+   The dynamic linkers has, as part of its debugger interface, support
+   for arranging for the inferior to hit a breakpoint after mapping in
+   the shared libraries.  This function enables that breakpoint.
+
+   On the FR-V, using the shared library (FDPIC) ABI, the symbol
+   _dl_debug_addr points to the r_debug struct which contains
+   a field called r_brk.  r_brk is the address of the function
+   descriptor upon which a breakpoint must be placed.  Being a
+   function descriptor, we must extract the entry point in order
+   to set the breakpoint.
+
+   Our strategy will be to get the .interp section from the
+   executable.  This section will provide us with the name of the
+   interpreter.  We'll open the interpreter and then look up
+   the address of _dl_debug_addr.  We then relocate this address
+   using the interpreter's loadmap.  Once the relocated address
+   is known, we fetch the value (address) corresponding to r_brk
+   and then use that value to fetch the entry point of the function
+   we're interested in.
+
+ */
+
+static int enable_break1_done = 0;
+static int enable_break2_done = 0;
+
+static int
+enable_break2 (void)
+{
+  int success = 0;
+  char **bkpt_namep;
+  asection *interp_sect;
+
+  if (!enable_break1_done || enable_break2_done)
+    return 1;
+
+  enable_break2_done = 1;
+
+  /* First, remove all the solib event breakpoints.  Their addresses
+     may have changed since the last time we ran the program.  */
+  remove_solib_event_breakpoints ();
+
+  interp_text_sect_low = interp_text_sect_high = 0;
+  interp_plt_sect_low = interp_plt_sect_high = 0;
+
+  /* Find the .interp section; if not found, warn the user and drop
+     into the old breakpoint at symbol code.  */
+  interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+  if (interp_sect)
+    {
+      unsigned int interp_sect_size;
+      char *buf;
+      bfd *tmp_bfd = NULL;
+      int tmp_fd = -1;
+      char *tmp_pathname = NULL;
+      int status;
+      CORE_ADDR addr, interp_loadmap_addr;
+      char addr_buf[FRV_PTR_SIZE];
+      struct int_elf32_fdpic_loadmap *ldm;
+
+      /* Read the contents of the .interp section into a local buffer;
+         the contents specify the dynamic linker this program uses.  */
+      interp_sect_size = bfd_section_size (exec_bfd, interp_sect);
+      buf = alloca (interp_sect_size);
+      bfd_get_section_contents (exec_bfd, interp_sect,
+				buf, 0, interp_sect_size);
+
+      /* Now we need to figure out where the dynamic linker was
+         loaded so that we can load its symbols and place a breakpoint
+         in the dynamic linker itself.
+
+         This address is stored on the stack.  However, I've been unable
+         to find any magic formula to find it for Solaris (appears to
+         be trivial on GNU/Linux).  Therefore, we have to try an alternate
+         mechanism to find the dynamic linker's base address.  */
+
+      tmp_fd  = solib_open (buf, &tmp_pathname);
+      if (tmp_fd >= 0)
+	tmp_bfd = bfd_fdopenr (tmp_pathname, gnutarget, tmp_fd);
+
+      if (tmp_bfd == NULL)
+	{
+	  enable_break_failure_warning ();
+	  return 0;
+	}
+
+      /* Make sure the dynamic linker is really a useful object.  */
+      if (!bfd_check_format (tmp_bfd, bfd_object))
+	{
+	  warning ("Unable to grok dynamic linker %s as an object file", buf);
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+
+      status = frv_fdpic_loadmap_addresses (current_gdbarch,
+                                            &interp_loadmap_addr, 0);
+      if (status < 0)
+	{
+	  warning ("Unable to determine dynamic linker loadmap address\n");
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+
+      if (solib_frv_debug)
+	fprintf_unfiltered (gdb_stdlog,
+	                    "enable_break: interp_loadmap_addr = %s\n",
+			    local_hex_string_custom (interp_loadmap_addr,
+			                             "08l"));
+
+      ldm = fetch_loadmap (interp_loadmap_addr);
+      if (ldm == NULL)
+	{
+	  warning ("Unable to load dynamic linker loadmap at address %s\n",
+	           local_hex_string_custom (interp_loadmap_addr, "08l"));
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+
+      /* Record the relocated start and end address of the dynamic linker
+         text and plt section for svr4_in_dynsym_resolve_code.  */
+      interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
+      if (interp_sect)
+	{
+	  interp_text_sect_low
+	    = bfd_section_vma (tmp_bfd, interp_sect);
+	  interp_text_sect_low
+	    += displacement_from_map (ldm, interp_text_sect_low);
+	  interp_text_sect_high
+	    = interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+	}
+      interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
+      if (interp_sect)
+	{
+	  interp_plt_sect_low =
+	    bfd_section_vma (tmp_bfd, interp_sect);
+	  interp_plt_sect_low
+	    += displacement_from_map (ldm, interp_plt_sect_low);
+	  interp_plt_sect_high =
+	    interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+	}
+
+      addr = bfd_lookup_symbol (tmp_bfd, "_dl_debug_addr");
+      if (addr == 0)
+	{
+	  warning ("Could not find symbol _dl_debug_addr in dynamic linker");
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+
+      if (solib_frv_debug)
+	fprintf_unfiltered (gdb_stdlog,
+	                    "enable_break: _dl_debug_addr (prior to relocation) = %s\n",
+			    local_hex_string_custom (addr, "08l"));
+
+      addr += displacement_from_map (ldm, addr);
+
+      if (solib_frv_debug)
+	fprintf_unfiltered (gdb_stdlog,
+	                    "enable_break: _dl_debug_addr (after relocation) = %s\n",
+			    local_hex_string_custom (addr, "08l"));
+
+      /* Fetch the address of the r_debug struct.  */
+      if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 0)
+	{
+	  warning ("Unable to fetch contents of _dl_debug_addr (at address %s) from dynamic linker",
+	           local_hex_string_custom (addr, "08l"));
+	}
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+
+      /* Fetch the r_brk field.  It's 8 bytes from the start of
+         _dl_debug_addr.  */
+      if (target_read_memory (addr + 8, addr_buf, sizeof addr_buf) != 0)
+	{
+	  warning ("Unable to fetch _dl_debug_addr->r_brk (at address %s) from dynamic linker",
+	           local_hex_string_custom (addr + 8, "08l"));
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+
+      /* Now fetch the function entry point.  */
+      if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 0)
+	{
+	  warning ("Unable to fetch _dl_debug_addr->.r_brk entry point (at address %s) from dynamic linker",
+	           local_hex_string_custom (addr, "08l"));
+	  enable_break_failure_warning ();
+	  bfd_close (tmp_bfd);
+	  return 0;
+	}
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+
+      /* We're done with the temporary bfd.  */
+      bfd_close (tmp_bfd);
+
+      /* We're also done with the loadmap.  */
+      xfree (ldm);
+
+      /* Now (finally!) create the solib breakpoint.  */
+      create_solib_event_breakpoint (addr);
+
+      return 1;
+    }
+
+  /* Tell the user we couldn't set a dynamic linker breakpoint.  */
+  enable_break_failure_warning ();
+
+  /* Failure return.  */
+  return 0;
+}
+
+static int
+enable_break (void)
+{
+  asection *interp_sect;
+
+  /* Remove all the solib event breakpoints.  Their addresses
+     may have changed since the last time we ran the program.  */
+  remove_solib_event_breakpoints ();
+
+  /* Check for the presence of a .interp section.  If there is no
+     such section, the executable is statically linked.  */
+
+  interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+
+  if (interp_sect)
+    {
+      enable_break1_done = 1;
+      create_solib_event_breakpoint (symfile_objfile->ei.entry_point);
+
+      if (solib_frv_debug)
+	fprintf_unfiltered (gdb_stdlog,
+			    "enable_break: solib event breakpoint placed at entry point: %s\n",
+			    local_hex_string_custom
+			      (symfile_objfile->ei.entry_point, "08l"));
+    }
+  else
+    {
+      if (solib_frv_debug)
+	fprintf_unfiltered (gdb_stdlog,
+	                    "enable_break: No .interp section found.\n");
+    }
+
+  return 1;
+}
+
+/*
+
+   LOCAL FUNCTION
+
+   special_symbol_handling -- additional shared library symbol handling
+
+   SYNOPSIS
+
+   void special_symbol_handling ()
+
+   DESCRIPTION
+
+   Once the symbols from a shared object have been loaded in the usual
+   way, we are called to do any system specific symbol handling that 
+   is needed.
+
+ */
+
+static void
+frv_special_symbol_handling (void)
+{
+  /* Nothing needed (yet) for FRV. */
+}
+
+static void
+frv_relocate_main_executable (void)
+{
+  int status;
+  CORE_ADDR exec_addr;
+  struct int_elf32_fdpic_loadmap *ldm;
+  struct cleanup *old_chain;
+  struct section_offsets *new_offsets;
+  int changed;
+  struct obj_section *osect;
+
+  status = frv_fdpic_loadmap_addresses (current_gdbarch, 0, &exec_addr);
+
+  if (status < 0)
+    {
+      /* Not using FDPIC ABI, so do nothing.  */
+      return;
+    }
+
+  /* Fetch the loadmap located at ``exec_addr''.  */
+  ldm = fetch_loadmap (exec_addr);
+  if (ldm == NULL)
+    error ("Unable to load the executable's loadmap.");
+
+  if (main_executable_lm_info)
+    xfree (main_executable_lm_info);
+  main_executable_lm_info = xcalloc (1, sizeof (struct lm_info));
+  main_executable_lm_info->map = ldm;
+
+  new_offsets = xcalloc (symfile_objfile->num_sections,
+			 sizeof (struct section_offsets));
+  old_chain = make_cleanup (xfree, new_offsets);
+  changed = 0;
+
+  ALL_OBJFILE_OSECTIONS (symfile_objfile, osect)
+    {
+      CORE_ADDR orig_addr, addr, offset;
+      int osect_idx;
+      int seg;
+      
+      osect_idx = osect->the_bfd_section->index;
+
+      /* Current address of section.  */
+      addr = osect->addr;
+      /* Offset from where this section started.  */
+      offset = ANOFFSET (symfile_objfile->section_offsets, osect_idx);
+      /* Original address prior to any past relocations.  */
+      orig_addr = addr - offset;
+
+      for (seg = 0; seg < ldm->nsegs; seg++)
+	{
+	  if (ldm->segs[seg].p_vaddr <= orig_addr
+	      && orig_addr < ldm->segs[seg].p_vaddr + ldm->segs[seg].p_memsz)
+	    {
+	      new_offsets->offsets[osect_idx]
+		= ldm->segs[seg].addr - ldm->segs[seg].p_vaddr;
+
+	      if (new_offsets->offsets[osect_idx] != offset)
+		changed = 1;
+	      break;
+	    }
+	}
+    }
+
+  if (changed)
+    objfile_relocate (symfile_objfile, new_offsets);
+
+  do_cleanups (old_chain);
+
+  /* Now that symfile_objfile has been relocated, we can compute the
+     GOT value and stash it away.  */
+  main_executable_lm_info->got_value = main_got ();
+}
+
+/*
+
+   GLOBAL FUNCTION
+
+   frv_solib_create_inferior_hook -- shared library startup support
+
+   SYNOPSIS
+
+   void frv_solib_create_inferior_hook()
+
+   DESCRIPTION
+
+   When gdb starts up the inferior, it nurses it along (through the
+   shell) until it is ready to execute it's first instruction.  At this
+   point, this function gets called via expansion of the macro
+   SOLIB_CREATE_INFERIOR_HOOK.
+
+   For the FR-V shared library ABI (FDPIC), the main executable
+   needs to be relocated.  The shared library breakpoints also need
+   to be enabled.
+ */
+
+static void
+frv_solib_create_inferior_hook (void)
+{
+  /* Relocate main executable.  */
+  frv_relocate_main_executable ();
+
+  /* Enable shared library breakpoints.  */
+  if (!enable_break ())
+    {
+      warning ("shared library handler failed to enable breakpoint");
+      return;
+    }
+}
+
+static void
+frv_clear_solib (void)
+{
+  lm_base_cache = 0;
+  enable_break1_done = 0;
+  enable_break2_done = 0;
+}
+
+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);
+}
+
+static void
+frv_relocate_section_addresses (struct so_list *so,
+                                 struct section_table *sec)
+{
+  int seg;
+  struct int_elf32_fdpic_loadmap *map;
+
+  map = so->lm_info->map;
+
+  for (seg = 0; seg < map->nsegs; seg++)
+    {
+      if (map->segs[seg].p_vaddr <= sec->addr
+          && sec->addr < map->segs[seg].p_vaddr + map->segs[seg].p_memsz)
+	{
+	  CORE_ADDR displ = map->segs[seg].addr - map->segs[seg].p_vaddr;
+	  sec->addr += displ;
+	  sec->endaddr += displ;
+	  break;
+	}
+    }
+}
+
+/* Return the GOT address associated with the main executable.  Return
+   0 if it can't be found.  */
+
+static CORE_ADDR
+main_got (void)
+{
+  struct minimal_symbol *got_sym;
+
+  got_sym = lookup_minimal_symbol ("_GLOBAL_OFFSET_TABLE_", NULL, symfile_objfile);
+  if (got_sym == 0)
+    return 0;
+
+  return SYMBOL_VALUE_ADDRESS (got_sym);
+}
+
+/* Find the global pointer for the given function address ADDR.  */
+
+CORE_ADDR
+frv_fdpic_find_global_pointer (CORE_ADDR addr)
+{
+  struct so_list *so;
+
+  so = master_so_list ();
+  while (so)
+    {
+      int seg;
+      struct int_elf32_fdpic_loadmap *map;
+
+      map = so->lm_info->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;
+	}
+
+      so = so->next;
+    }
+
+  /* Didn't find it it any of the shared objects.  So assume it's in the
+     main executable.  */
+  return main_got ();
+}
+
+/* Forward declarations for frv_fdpic_find_canonical_descriptor().  */
+static CORE_ADDR find_canonical_descriptor_in_load_object
+  (CORE_ADDR, CORE_ADDR, char *, bfd *, struct lm_info *);
+
+/* Given a function entry point, attempt to find the canonical descriptor
+   associated with that entry point.  Return 0 if no canonical descriptor
+   could be found.  */
+
+CORE_ADDR
+frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point)
+{
+  char *name;
+  CORE_ADDR addr;
+  CORE_ADDR got_value;
+  struct int_elf32_fdpic_loadmap *ldm = 0;
+  struct symbol *sym;
+  int status;
+  CORE_ADDR exec_loadmap_addr;
+
+  /* Fetch the corresponding global pointer for the entry point.  */
+  got_value = frv_fdpic_find_global_pointer (entry_point);
+
+  /* Attempt to find the name of the function.  If the name is available,
+     it'll be used as an aid in finding matching functions in the dynamic
+     symbol table.  */
+  sym = find_pc_function (entry_point);
+  if (sym == 0)
+    name = 0;
+  else
+    name = SYMBOL_LINKAGE_NAME (sym);
+
+  /* Check the main executable.  */
+  addr = find_canonical_descriptor_in_load_object
+           (entry_point, got_value, name, symfile_objfile->obfd,
+	    main_executable_lm_info);
+
+  /* If descriptor not found via main executable, check each load object
+     in list of shared objects.  */
+  if (addr == 0)
+    {
+      struct so_list *so;
+
+      so = master_so_list ();
+      while (so)
+	{
+	  addr = find_canonical_descriptor_in_load_object
+		   (entry_point, got_value, name, so->abfd, so->lm_info);
+
+	  if (addr != 0)
+	    break;
+
+	  so = so->next;
+	}
+    }
+
+  return addr;
+}
+
+static CORE_ADDR
+find_canonical_descriptor_in_load_object
+  (CORE_ADDR entry_point, CORE_ADDR got_value, char *name, bfd *abfd,
+   struct lm_info *lm)
+{
+  arelent *rel;
+  unsigned int i;
+  CORE_ADDR addr = 0;
+
+  /* Nothing to do if no bfd.  */
+  if (abfd == 0)
+    return 0;
+
+  /* We want to scan the dynamic relocs for R_FRV_FUNCDESC relocations.
+     (More about this later.)  But in order to fetch the relocs, we
+     need to first fetch the dynamic symbols.  These symbols need to
+     be cached due to the way that bfd_canonicalize_dynamic_reloc()
+     works.  (See the comments in the declaration of struct lm_info
+     for more information.)  */
+  if (lm->dyn_syms == NULL)
+    {
+      long storage_needed;
+      unsigned int number_of_symbols;
+
+      /* Determine amount of space needed to hold the dynamic symbol table.  */
+      storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+
+      /* If there are no dynamic symbols, there's nothing to do.  */
+      if (storage_needed <= 0)
+	return 0;
+
+      /* Allocate space for the dynamic symbol table.  */
+      lm->dyn_syms = (asymbol **) xmalloc (storage_needed);
+
+      /* Fetch the dynamic symbol table.  */
+      number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, lm->dyn_syms);
+
+      if (number_of_symbols == 0)
+	return 0;
+    }
+
+  /* Fetch the dynamic relocations if not already cached.  */
+  if (lm->dyn_relocs == NULL)
+    {
+      long storage_needed;
+
+      /* Determine amount of space needed to hold the dynamic relocs.  */
+      storage_needed = bfd_get_dynamic_reloc_upper_bound (abfd);
+
+      /* Bail out if there are no dynamic relocs.  */
+      if (storage_needed <= 0)
+	return 0;
+
+      /* Allocate space for the relocs.  */
+      lm->dyn_relocs = (arelent **) xmalloc (storage_needed);
+
+      /* Fetch the dynamic relocs.  */
+      lm->dyn_reloc_count 
+	= bfd_canonicalize_dynamic_reloc (abfd, lm->dyn_relocs, lm->dyn_syms);
+    }
+
+  /* Search the dynamic relocs.  */
+  for (i = 0; i < lm->dyn_reloc_count; i++)
+    {
+      rel = lm->dyn_relocs[i];
+
+      /* Relocs of interest are those which meet the following
+         criteria:
+
+	   - the names match (assuming the caller could provide
+	     a name which matches ``entry_point'').
+	   - the relocation type must be R_FRV_FUNCDESC.  Relocs
+	     of this type are used (by the dynamic linker) to
+	     look up the address of a canonical descriptor (allocating
+	     it if need be) and initializing the GOT entry referred
+	     to by the offset to the address of the descriptor.
+
+	 These relocs of interest may be used to obtain a
+	 candidate descriptor by first adjusting the reloc's
+	 address according to the link map and then dereferencing
+	 this address (which is a GOT entry) to obtain a descriptor
+	 address.  */
+      if ((name == 0 || strcmp (name, (*rel->sym_ptr_ptr)->name) == 0)
+          && rel->howto->type == R_FRV_FUNCDESC)
+	{
+	  char buf[FRV_PTR_SIZE];
+
+	  /* Compute address of address of candidate descriptor.  */
+	  addr = rel->address + displacement_from_map (lm->map, rel->address);
+
+	  /* Fetch address of candidate descriptor.  */
+	  if (target_read_memory (addr, buf, sizeof buf) != 0)
+	    continue;
+	  addr = extract_unsigned_integer (buf, sizeof buf);
+
+	  /* Check for matching entry point.  */
+	  if (target_read_memory (addr, buf, sizeof buf) != 0)
+	    continue;
+	  if (extract_unsigned_integer (buf, sizeof buf) != entry_point)
+	    continue;
+
+	  /* Check for matching got value.  */
+	  if (target_read_memory (addr + 4, buf, sizeof buf) != 0)
+	    continue;
+	  if (extract_unsigned_integer (buf, sizeof buf) != got_value)
+	    continue;
+
+	  /* Match was successful!  Exit loop.  */
+	  break;
+	}
+    }
+
+  return addr;
+}
+
+static struct target_so_ops frv_so_ops;
+
+void
+_initialize_frv_solib (void)
+{
+  frv_so_ops.relocate_section_addresses = frv_relocate_section_addresses;
+  frv_so_ops.free_so = frv_free_so;
+  frv_so_ops.clear_solib = frv_clear_solib;
+  frv_so_ops.solib_create_inferior_hook = frv_solib_create_inferior_hook;
+  frv_so_ops.special_symbol_handling = frv_special_symbol_handling;
+  frv_so_ops.current_sos = frv_current_sos;
+  frv_so_ops.open_symbol_file_object = open_symbol_file_object;
+  frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code;
+
+  /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */
+  current_target_so_ops = &frv_so_ops;
+
+  /* Debug this file's internals.  */
+  add_show_from_set (add_set_cmd ("solib-frv", class_maintenance, var_zinteger,
+				  &solib_frv_debug,
+"Set internal debugging of shared library code for FR-V.\n"
+"When non-zero, FR-V solib specific internal debugging is enabled.",
+                                  &setdebuglist),
+		     &showdebuglist);
+}
Index: config/frv/frv.mt
===================================================================
RCS file: /cvs/src/src/gdb/config/frv/frv.mt,v
retrieving revision 1.2
diff -u -p -r1.2 frv.mt
--- config/frv/frv.mt	8 Sep 2003 23:21:37 -0000	1.2
+++ config/frv/frv.mt	13 Mar 2004 00:39:58 -0000
@@ -1,5 +1,5 @@
 # Target: Fujitsu FRV processor
-TDEPFILES= frv-tdep.o
+TDEPFILES= frv-tdep.o solib.o solib-frv.o
 TM_FILE= tm-frv.h
 SIM_OBS = remote-sim.o
 SIM = ../sim/frv/libsim.a
Index: config/frv/tm-frv.h
===================================================================
RCS file: /cvs/src/src/gdb/config/frv/tm-frv.h,v
retrieving revision 1.3
diff -u -p -r1.3 tm-frv.h
--- config/frv/tm-frv.h	3 Sep 2003 15:02:49 -0000	1.3
+++ config/frv/tm-frv.h	13 Mar 2004 00:39:58 -0000
@@ -43,3 +43,5 @@ extern CORE_ADDR frv_stopped_data_addres
 
 /* Use these macros for watchpoint insertion/deletion.  */
 #define target_stopped_data_address() frv_stopped_data_address()
+
+#include "solib.h"		/* Include support for shared libraries.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]