* Makefile.in (osfsolib.c, osfsolib.o): Rename to solib-osf.c and
authorNicholas Duffek <nsd@redhat.com>
Sat, 26 May 2001 00:52:15 +0000 (00:52 +0000)
committerNicholas Duffek <nsd@redhat.com>
Sat, 26 May 2001 00:52:15 +0000 (00:52 +0000)
solib-osf.o.
* config/alpha/alpha-osf1.mh (NATDEPFILES): Replace osfsolib.o
with solib-osf.o and solib.o.
* config/alpha/alpha-osf2.mh: Likewise.
* config/alpha/alpha-osf3.mh: Likewise.
* solib-osf.c: New file, renamed and largely rewritten from
osfsolib.c.

gdb/ChangeLog
gdb/Makefile.in
gdb/config/alpha/alpha-osf1.mh
gdb/config/alpha/alpha-osf2.mh
gdb/config/alpha/alpha-osf3.mh
gdb/solib-osf.c [new file with mode: 0644]

index bda56c64c94d4436c247699dd02aa06df9ccb07a..e20163a0ca85cb8a44aaca2e6f1a66cc555d857b 100644 (file)
@@ -1,3 +1,14 @@
+2001-05-25  Nick Duffek  <nsd@redhat.com>
+
+       * Makefile.in (osfsolib.c, osfsolib.o): Rename to solib-osf.c and
+       solib-osf.o.
+       * config/alpha/alpha-osf1.mh (NATDEPFILES): Replace osfsolib.o
+       with solib-osf.o and solib.o.
+       * config/alpha/alpha-osf2.mh: Likewise.
+       * config/alpha/alpha-osf3.mh: Likewise.
+       * solib-osf.c: New file, renamed and largely rewritten from
+       osfsolib.c.
+
 2001-05-25  Michael Snyder  <msnyder@redhat.com>
 
        * remote.c (remote_write_bytes): Update 'p' packet pointer.
index 6735215d428212f51ea61f5c86bbdd57f3d9596f..6049ab4620139207517af0a493a711a3ec1be257 100644 (file)
@@ -1163,7 +1163,7 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \
        mips-tdep.c mipsm3-nat.c mipsv4-nat.c news-xdep.c \
        nindy-share/Onindy.c nindy-share/nindy.c \
        nindy-share/ttyflush.c nindy-tdep.c \
-       ns32k-tdep.c osfsolib.c \
+       ns32k-tdep.c solib-osf.c \
        somread.c somsolib.c $(HPREAD_SOURCE) \
        ppc-linux-nat.c ppc-linux-tdep.c \
        procfs.c \
@@ -1730,8 +1730,8 @@ ns32k-tdep.o: ns32k-tdep.c $(bfd_h) $(dis-asm_h) $(defs_h)
 objfiles.o: objfiles.c $(bfd_h) $(defs_h) objfiles.h symfile.h \
        $(symtab_h) $(gdb_string_h) $(breakpoint_h)
 
-osfsolib.o: osfsolib.c $(command_h) $(defs_h) $(gdbcore_h) $(inferior_h) \
-       objfiles.h gnu-regex.h symfile.h target.h language.h $(gdb_string_h)
+solib-osf.o: solib-osf.c $(defs_h) $(inferior_h) $(symtab_h) objfiles.h \
+       $(symfile_h) $(target_h) $(gdb_string_h) solist.h
 
 somread.o: somread.c $(bfd_h) buildsym.h complaints.h $(defs_h) \
        gdb-stabs.h objfiles.h symfile.h $(symtab_h) $(gdb_string_h)
index 6ed0f95ffcf63d031769ea30df5ecda310118c58..62654e8c00c50681b6460e724af589a2153673fd 100644 (file)
@@ -2,4 +2,5 @@
 XDEPFILES= 
 XM_FILE= xm-alphaosf.h
 NAT_FILE= nm-osf.h
-NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o osfsolib.o
+NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \
+       solib-osf.o solib.o
index bb200d8236ed7ae6b8f840da1fa15ee42e61940e..8b4d841c960bee53f110199bc182208e4587d77f 100644 (file)
@@ -3,4 +3,5 @@ XDEPFILES=
 XM_FILE= xm-alphaosf.h
 NAT_FILE= nm-osf2.h
 NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \
-       osfsolib.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
+       solib-osf.o solib.o procfs.o proc-api.o proc-events.o proc-flags.o \
+       proc-why.o
index 6af28084d660f927a784e3948cd7db8c7da64e51..1ad20856a8bb92fdc8a8b6210adbffe5f8b41c65 100644 (file)
@@ -3,5 +3,5 @@ XDEPFILES=
 XM_FILE= xm-alphaosf.h
 NAT_FILE= nm-osf3.h
 NATDEPFILES= infptrace.o inftarg.o corelow.o alpha-nat.o fork-child.o \
-       osfsolib.o procfs.o proc-api.o proc-events.o proc-flags.o proc-why.o
-
+       solib-osf.o solib.o procfs.o proc-api.o proc-events.o proc-flags.o \
+       proc-why.o
diff --git a/gdb/solib-osf.c b/gdb/solib-osf.c
new file mode 100644 (file)
index 0000000..805254f
--- /dev/null
@@ -0,0 +1,611 @@
+/* Handle OSF/1, Digital UNIX, and Tru64 shared libraries
+   for GDB, the GNU Debugger.
+   Copyright 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+   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.  */
+
+/* When handling shared libraries, GDB has to find out the pathnames
+   of all shared libraries that are currently loaded (to read in their
+   symbols) and where the shared libraries are loaded in memory
+   (to relocate them properly from their prelinked addresses to the
+   current load address).
+
+   Under OSF/1 there are two possibilities to get at this information:
+
+   1) Peek around in the runtime loader structures.
+   These are not documented, and they are not defined in the system
+   header files. The definitions below were obtained by experimentation,
+   but they seem stable enough.
+
+   2) Use the libxproc.a library, which contains the equivalent ldr_*
+   routines.  The library is documented in Tru64 5.x, but as of 5.1, it
+   only allows a process to examine itself.  On earlier versions, it
+   may require that the GDB executable be dynamically linked and that
+   NAT_CLIBS include -lxproc -Wl,-expect_unresolved,ldr_process_context
+   for GDB and all applications that are using libgdb.
+
+   We will use the peeking approach until libxproc.a works for other
+   processes.  */
+
+#include "defs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include "gdb_string.h"
+
+#include "bfd.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "target.h"
+#include "inferior.h"
+#include "solist.h"
+
+#ifdef USE_LDR_ROUTINES
+# include <loader.h>
+#endif
+
+#ifndef USE_LDR_ROUTINES
+/* Definition of runtime loader structures, found by experimentation.  */
+#define RLD_CONTEXT_ADDRESS    0x3ffc0000000
+
+/* Per-module information structure referenced by ldr_context_t.head.  */
+
+typedef struct
+  {
+    CORE_ADDR next;
+    CORE_ADDR previous;
+    CORE_ADDR unknown1;
+    CORE_ADDR module_name;
+    CORE_ADDR modinfo_addr;    /* used by next_link_map_member() to detect
+                                  the end of the shared module list */
+    long module_id;
+    CORE_ADDR unknown2;
+    CORE_ADDR unknown3;
+    long region_count;
+    CORE_ADDR regioninfo_addr;
+  }
+ldr_module_info_t;
+
+/* Per-region structure referenced by ldr_module_info_t.regioninfo_addr.  */
+
+typedef struct
+  {
+    long unknown1;
+    CORE_ADDR regionname_addr;
+    long protection;
+    CORE_ADDR vaddr;
+    CORE_ADDR mapaddr;
+    long size;
+    long unknown2[5];
+  }
+ldr_region_info_t;
+
+/* Structure at RLD_CONTEXT_ADDRESS specifying the start and finish addresses
+   of the shared module list.  */
+
+typedef struct
+  {
+    CORE_ADDR unknown1;
+    CORE_ADDR unknown2;
+    CORE_ADDR head;
+    CORE_ADDR tail;
+  }
+ldr_context_t;
+#endif   /* !USE_LDR_ROUTINES */
+
+/* Per-section information, stored in struct lm_info.secs.  */
+
+struct lm_sec
+  {
+    CORE_ADDR offset;          /* difference between default and actual
+                                  virtual addresses of section .name */
+    CORE_ADDR nameaddr;                /* address in inferior of section name */
+    const char *name;          /* name of section, null if not fetched */
+  };
+
+/* Per-module information, stored in struct so_list.lm_info.  */
+
+struct lm_info
+  {
+    int isloader;              /* whether the module is /sbin/loader */
+    int nsecs;                 /* length of .secs */
+    struct lm_sec secs[1];     /* variable-length array of sections, sorted
+                                  by name */
+  };
+
+/* Context for iterating through the inferior's shared module list.  */
+
+struct read_map_ctxt
+  {
+#ifdef USE_LDR_ROUTINES
+    ldr_process_t proc;
+    ldr_module_t next;
+#else
+    CORE_ADDR next;            /* next element in module list */
+    CORE_ADDR tail;            /* last element in module list */
+#endif
+  };
+
+/* Forward declaration for this module's autoinit function.  */
+
+extern void _initialize_osf_solib (void);
+
+#ifdef USE_LDR_ROUTINES
+# if 0
+/* This routine is intended to be called by ldr_* routines to read memory from
+   the current target.  Usage:
+
+     ldr_process = ldr_core_process ();
+     ldr_set_core_reader (ldr_read_memory);
+     ldr_xdetach (ldr_process);
+     ldr_xattach (ldr_process);
+
+   ldr_core_process() and ldr_read_memory() are neither documented nor
+   declared in system header files.  They work with OSF/1 2.x, and they might
+   work with later versions as well.  */
+
+static int
+ldr_read_memory (CORE_ADDR memaddr, char *myaddr, int len, int readstring)
+{
+  int result;
+  char *buffer;
+
+  if (readstring)
+    {
+      target_read_string (memaddr, &buffer, len, &result);
+      if (result == 0)
+       strcpy (myaddr, buffer);
+      xfree (buffer);
+    }
+  else
+    result = target_read_memory (memaddr, myaddr, len);
+
+  if (result != 0)
+    result = -result;
+  return result;
+}
+# endif   /* 0 */
+#endif   /* USE_LDR_ROUTINES */
+
+/* Comparison for qsort() and bsearch(): return -1, 0, or 1 according to
+   whether lm_sec *P1's name is lexically less than, equal to, or greater
+   than that of *P2.  */
+
+static int
+lm_sec_cmp (const void *p1, const void *p2)
+{
+  const struct lm_sec *lms1 = p1, *lms2 = p2;
+  return strcmp (lms1->name, lms2->name);
+}
+
+/* Sort LMI->secs so that osf_relocate_section_addresses() can binary-search
+   it.  */
+
+static void
+lm_secs_sort (struct lm_info *lmi)
+{
+  qsort (lmi->secs, lmi->nsecs, sizeof *lmi->secs, lm_sec_cmp);
+}
+
+/* Populate name fields of LMI->secs.  */
+
+static void
+fetch_sec_names (struct lm_info *lmi)
+{
+#ifndef USE_LDR_ROUTINES
+  int i, errcode;
+  struct lm_sec *lms;
+  char *name;
+
+  for (i = 0; i < lmi->nsecs; i++)
+    {
+      lms = lmi->secs + i;
+      target_read_string (lms->nameaddr, &name, PATH_MAX, &errcode);
+      if (errcode != 0)
+       {
+         warning ("unable to read shared sec name at 0x%lx", lms->nameaddr);
+         name = xstrdup ("");
+       }
+      lms->name = name;
+    }
+  lm_secs_sort (lmi);
+#endif
+}
+
+/* target_so_ops callback.  Adjust SEC's addresses after it's been mapped into
+   the process.  */
+
+static void
+osf_relocate_section_addresses (struct so_list *so,
+                               struct section_table *sec)
+{
+  struct lm_info *lmi;
+  struct lm_sec lms_key, *lms;
+
+  /* Fetch SO's section names if we haven't done so already.  */
+  lmi = so->lm_info;
+  if (lmi->nsecs && !lmi->secs[0].name)
+    fetch_sec_names (lmi);
+
+  /* Binary-search for offset information corresponding to SEC.  */
+  lms_key.name = sec->the_bfd_section->name;
+  lms = bsearch (&lms_key, lmi->secs, lmi->nsecs, sizeof *lms, lm_sec_cmp);
+  if (lms)
+    {
+      sec->addr += lms->offset;
+      sec->endaddr += lms->offset;
+    }
+}
+
+/* target_so_ops callback.  Free parts of SO allocated by this file.  */
+
+static void
+osf_free_so (struct so_list *so)
+{
+  int i;
+  const char *name;
+
+  for (i = 0; i < so->lm_info->nsecs; i++)
+    {
+      name = so->lm_info->secs[i].name;
+      if (name)
+       xfree ((void *) name);
+    }
+  xfree (so->lm_info);
+}
+
+/* target_so_ops callback.  Discard information accumulated by this file and
+   not freed by osf_free_so().  */
+
+static void
+osf_clear_solib (void)
+{
+  return;
+}
+
+/* target_so_ops callback.  Prepare to handle shared libraries after the
+   inferior process has been created but before it's executed any
+   instructions.
+
+   For a statically bound executable, the inferior's first instruction is the
+   one at "_start", or a similar text label. No further processing is needed
+   in that case.
+
+   For a dynamically bound executable, this first instruction is somewhere
+   in the rld, and the actual user executable is not yet mapped in.
+   We continue the inferior again, rld then maps in the actual user
+   executable and any needed shared libraries and then sends
+   itself a SIGTRAP.
+
+   At that point we discover the names of all shared libraries and
+   read their symbols in.
+
+   FIXME
+
+   This code does not properly handle hitting breakpoints which the
+   user might have set in the rld itself.  Proper handling would have
+   to check if the SIGTRAP happened due to a kill call.
+
+   Also, what if child has exit()ed?  Must exit loop somehow.  */
+
+static void
+osf_solib_create_inferior_hook (void)
+{
+  /* Nothing to do for statically bound executables.  */
+
+  if (symfile_objfile == NULL
+      || symfile_objfile->obfd == NULL
+      || ((bfd_get_file_flags (symfile_objfile->obfd) & DYNAMIC) == 0))
+    return;
+
+  /* Now run the target.  It will eventually get a SIGTRAP, at
+     which point all of the libraries will have been mapped in and we
+     can go groveling around in the rld structures to find
+     out what we need to know about them. */
+
+  clear_proceed_status ();
+  stop_soon_quietly = 1;
+  stop_signal = TARGET_SIGNAL_0;
+  do
+    {
+      target_resume (minus_one_ptid, 0, stop_signal);
+      wait_for_inferior ();
+    }
+  while (stop_signal != TARGET_SIGNAL_TRAP);
+
+  /*  solib_add will call reinit_frame_cache.
+     But we are stopped in the runtime loader and we do not have symbols
+     for the runtime loader. So heuristic_proc_start will be called
+     and will put out an annoying warning.
+     Delaying the resetting of stop_soon_quietly until after symbol loading
+     suppresses the warning.  */
+  if (auto_solib_add)
+    solib_add ((char *) 0, 0, (struct target_ops *) 0);
+  stop_soon_quietly = 0;
+
+  /* Enable breakpoints disabled (unnecessarily) by clear_solib().  */
+  re_enable_breakpoints_in_shlibs ();
+}
+
+/* target_so_ops callback.  Do additional symbol handling, lookup, etc. after
+   symbols for a shared object have been loaded.  */
+
+static void
+osf_special_symbol_handling (void)
+{
+  return;
+}
+
+/* Initialize CTXT in preparation for iterating through the inferior's module
+   list using read_map().  Return success.  */
+
+static int
+open_map (struct read_map_ctxt *ctxt)
+{
+#ifdef USE_LDR_ROUTINES
+  ctxt->proc = ldr_my_process ();
+  if (ldr_xattach (ctxt->proc) != 0)
+    return 0;
+  ctxt->next = LDR_NULL_MODULE;
+#else
+  CORE_ADDR ldr_context_addr, prev, next;
+  ldr_context_t ldr_context;
+
+  if (target_read_memory ((CORE_ADDR) RLD_CONTEXT_ADDRESS,
+                         (char *) &ldr_context_addr,
+                         sizeof (CORE_ADDR)) != 0)
+    return 0;
+  if (target_read_memory (ldr_context_addr,
+                         (char *) &ldr_context,
+                         sizeof (ldr_context_t)) != 0)
+    return 0;
+  ctxt->next = ldr_context.head;
+  ctxt->tail = ldr_context.tail;
+#endif
+  return 1;
+}
+
+/* Initialize SO to have module NAME, /sbin/loader indicator ISLOADR, and
+   space for NSECS sections.  */
+
+static void
+init_so (struct so_list *so, char *name, int isloader, int nsecs)
+{
+  int namelen, i;
+
+  /* solib.c requires various fields to be initialized to 0.  */
+  memset (so, 0, sizeof *so);
+
+  /* Copy the name.  */
+  namelen = strlen (name);
+  if (namelen >= SO_NAME_MAX_PATH_SIZE)
+    namelen = SO_NAME_MAX_PATH_SIZE - 1;
+
+  memcpy (so->so_original_name, name, namelen);
+  so->so_original_name[namelen] = '\0';
+  memcpy (so->so_name, so->so_original_name, namelen + 1);
+
+  /* Allocate section space.  */
+  so->lm_info = xmalloc ((unsigned) &(((struct lm_info *)0)->secs) +
+                        nsecs * sizeof *so->lm_info);
+  so->lm_info->isloader = isloader;
+  so->lm_info->nsecs = nsecs;
+  for (i = 0; i < nsecs; i++)
+    so->lm_info->secs[i].name = NULL;
+}
+
+/* Initialize SO's section SECIDX with name address NAMEADDR, name string
+   NAME, default virtual address VADDR, and actual virtual address
+   MAPADDR.  */
+
+static void
+init_sec (struct so_list *so, int secidx, CORE_ADDR nameaddr,
+         const char *name, CORE_ADDR vaddr, CORE_ADDR mapaddr)
+{
+  struct lm_sec *lms;
+
+  lms = so->lm_info->secs + secidx;
+  lms->nameaddr = nameaddr;
+  lms->name = name;
+  lms->offset = mapaddr - vaddr;
+}
+
+/* If there are more elements starting at CTXT in inferior's module list,
+   store the next element in SO, advance CTXT to the next element, and return
+   1, else return 0.  */
+
+static int
+read_map (struct read_map_ctxt *ctxt, struct so_list *so)
+{
+  ldr_module_info_t minf;
+  ldr_region_info_t rinf;
+
+#ifdef USE_LDR_ROUTINES
+  size_t size;
+  ldr_region_t i;
+
+  /* Retrieve the next element.  */
+  if (ldr_next_module (ctxt->proc, &ctxt->next) != 0)
+    return 0;
+  if (ctxt->next == LDR_NULL_MODULE)
+    return 0;
+  if (ldr_inq_module (ctxt->proc, ctxt->next, &minf, sizeof minf, &size) != 0)
+    return 0;
+
+  /* Initialize the module name and section count.  */
+  init_so (so, minf.lmi_name, 0, minf.lmi_nregion);
+
+  /* Retrieve section names and offsets.  */
+  for (i = 0; i < minf.lmi_nregion; i++)
+    {
+      if (ldr_inq_region (ctxt->proc, ctxt->next, i, &rinf,
+                         sizeof rinf, &size) != 0)
+       goto err;
+      init_sec (so, (int) i, 0, xstrdup (rinf.lri_name),
+               (CORE_ADDR) rinf.lri_vaddr, (CORE_ADDR) rinf.lri_mapaddr);
+    }
+  lm_secs_sort (so->lm_info);
+#else
+  char *name;
+  int errcode, i;
+
+  /* Retrieve the next element.  */
+  if (!ctxt->next)
+    return 0;
+  if (target_read_memory (ctxt->next, (char *) &minf, sizeof minf) != 0)
+    return 0;
+  if (ctxt->next == ctxt->tail)
+    ctxt->next = 0;
+  else
+    ctxt->next = minf.next;
+
+  /* Initialize the module name and section count.  */
+  target_read_string (minf.module_name, &name, PATH_MAX, &errcode);
+  if (errcode != 0)
+    return 0;
+  init_so (so, name, !minf.modinfo_addr, minf.region_count);
+  xfree (name);
+
+  /* Retrieve section names and offsets.  */
+  for (i = 0; i < minf.region_count; i++)
+    {
+      if (target_read_memory (minf.regioninfo_addr + i * sizeof rinf,
+                             (char *) &rinf, sizeof rinf) != 0)
+       goto err;
+      init_sec (so, i, rinf.regionname_addr, NULL, rinf.vaddr, rinf.mapaddr);
+    }
+#endif   /* !USE_LDR_ROUTINES */
+  return 1;
+
+ err:
+  osf_free_so (so);
+  return 0;
+}
+
+/* Free resources allocated by open_map (CTXT).  */
+
+static void
+close_map (struct read_map_ctxt *ctxt)
+{
+#ifdef USE_LDR_ROUTINES
+  ldr_xdetach (ctxt->proc);
+#endif
+}
+
+/* target_so_ops callback.  Return a list of shared objects currently loaded
+   in the inferior.  */
+
+static struct so_list *
+osf_current_sos (void)
+{
+  struct so_list *head = NULL, *tail, *newtail, so;
+  struct read_map_ctxt ctxt;
+  int skipped_main;
+
+  if (!open_map (&ctxt))
+    return NULL;
+
+  /* Read subsequent elements.  */
+  for (skipped_main = 0;;)
+    {
+      if (!read_map (&ctxt, &so))
+       break;
+
+      /* Skip the main program module, which is first in the list after
+         /sbin/loader.  */
+      if (!so.lm_info->isloader && !skipped_main)
+       {
+         osf_free_so (&so);
+         skipped_main = 1;
+         continue;
+       }
+
+      newtail = xmalloc (sizeof *newtail);
+      if (!head)
+       head = newtail;
+      else
+       tail->next = newtail;
+      tail = newtail;
+
+      memcpy (tail, &so, sizeof so);
+      tail->next = NULL;
+    }
+
+ done:
+  close_map (&ctxt);
+  return head;
+}
+
+/* target_so_ops callback.  Attempt to locate and open the main symbol
+   file.  */
+
+static int
+osf_open_symbol_file_object (void *from_ttyp)
+{
+  struct read_map_ctxt ctxt;
+  struct so_list so;
+  int found;
+
+  if (symfile_objfile)
+    if (!query ("Attempt to reload symbols from process? "))
+      return 0;
+
+  /* The first module after /sbin/loader is the main program.  */
+  if (!open_map (&ctxt))
+    return 0;
+  for (found = 0; !found;)
+    {
+      if (!read_map (&ctxt, &so))
+       break;
+      found = !so.lm_info->isloader;
+      osf_free_so (&so);
+    }
+  close_map (&ctxt);
+
+  if (found)
+    symbol_file_add_main (so.so_name, *(int *) from_ttyp);
+  return found;
+}
+
+/* target_so_ops callback.  Return whether PC is in the dynamic linker.  */
+
+static int
+osf_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  return 0;
+}
+
+static struct target_so_ops osf_so_ops;
+
+void
+_initialize_osf_solib (void)
+{
+  osf_so_ops.relocate_section_addresses = osf_relocate_section_addresses;
+  osf_so_ops.free_so = osf_free_so;
+  osf_so_ops.clear_solib = osf_clear_solib;
+  osf_so_ops.solib_create_inferior_hook = osf_solib_create_inferior_hook;
+  osf_so_ops.special_symbol_handling = osf_special_symbol_handling;
+  osf_so_ops.current_sos = osf_current_sos;
+  osf_so_ops.open_symbol_file_object = osf_open_symbol_file_object;
+  osf_so_ops.in_dynsym_resolve_code = osf_in_dynsym_resolve_code;
+
+  /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */
+  current_target_so_ops = &osf_so_ops;
+}