* TODO: Add item suggesting an "info bfd" command.
[deliverable/binutils-gdb.git] / gdb / osfsolib.c
index 55d20cfd6e80d7dec46148799ee211011a62eae5..85afa24211c73566a555d0550ca5ebf948a0c903 100644 (file)
@@ -1,5 +1,5 @@
 /* Handle OSF/1 shared libraries for GDB, the GNU Debugger.
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
    
 This file is part of GDB.
 
@@ -15,7 +15,7 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 /* FIXME: Most of this code could be merged with solib.c by using
    next_link_map_member and xfer_link_map_member in solib.c.  */
@@ -24,7 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <sys/types.h>
 #include <signal.h>
-#include <string.h>
+#include "gdb_string.h"
 #include <fcntl.h>
 
 #include "symtab.h"
@@ -35,30 +35,63 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "command.h"
 #include "target.h"
 #include "frame.h"
-#include "regex.h"
+#include "gnu-regex.h"
 #include "inferior.h"
 #include "language.h"
-
-#define MAX_PATH_SIZE 256              /* FIXME: Should be dynamic */
-
-/* FIXME: This is a terrible hack for shared library support under OSF/1.
-   The main problem is that the needed definitions are not contained in
-   the system header files.
-   The ldr_* routines described in loader(3) would be the way to go here.
-   But they do not work for arbitrary target processes (as documented).  */
+#include "gdbcmd.h"
+
+#define MAX_PATH_SIZE 1024             /* FIXME: Should be dynamic */
+
+/* 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 undocumented libxproc.a library, which contains the
+      equivalent ldr_* routines.
+      This approach is somewhat cleaner, but it requires that the GDB
+      executable is dynamically linked. In addition it requires a
+      NAT_CLIBS= -lxproc -Wl,-expect_unresolved,ldr_process_context
+      linker specification for GDB and all applications that are using
+      libgdb.
+   We will use the peeking approach until it becomes unwieldy.  */
 
 #ifndef USE_LDR_ROUTINES
+
+/* Definition of runtime loader structures, found by experimentation.  */
 #define RLD_CONTEXT_ADDRESS    0x3ffc0000000
 
 typedef struct
 {
        CORE_ADDR next;
        CORE_ADDR previous;
-       CORE_ADDR unknown;
+       CORE_ADDR unknown1;
        char *module_name;
        CORE_ADDR modinfo_addr;
+       long module_id;
+       CORE_ADDR unknown2;
+       CORE_ADDR unknown3;
+       long region_count;
+       CORE_ADDR regioninfo_addr;
 } ldr_module_info_t;
 
+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;
+
 typedef struct
 {
        CORE_ADDR unknown1;
@@ -68,20 +101,53 @@ typedef struct
 } ldr_context_t;
 
 static ldr_context_t ldr_context;
+
 #else
+
 #include <loader.h>
+static ldr_process_t fake_ldr_process;
+
+/* Called by ldr_* routines to read memory from the current target.  */
+
+static int ldr_read_memory PARAMS ((CORE_ADDR, char *, int, int));
+
+static int
+ldr_read_memory (memaddr, myaddr, len, readstring)
+     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);
+      free (buffer);
+    }
+  else
+    result = target_read_memory (memaddr, myaddr, len);
+
+  if (result != 0)
+    result = -result;
+  return result;
+}
+
 #endif
 
 /* Define our own link_map structure.
    This will help to share code with solib.c.  */
 
 struct link_map {
-  CORE_ADDR l_addr;                    /* address at which object mapped */
+  CORE_ADDR l_offset;                  /* prelink to load address offset */
   char *l_name;                                /* full name of loaded object */
   ldr_module_info_t module_info;       /* corresponding module info */
 };
 
-#define LM_ADDR(so) ((so) -> lm.l_addr)
+#define LM_OFFSET(so) ((so) -> lm.l_offset)
 #define LM_NAME(so) ((so) -> lm.l_name)
 
 struct so_list {
@@ -209,12 +275,12 @@ solib_map_sections (so)
   for (p = so -> sections; p < so -> sections_end; p++)
     {
       /* Relocate the section binding addresses as recorded in the shared
-        object's file by the base address to which the object was actually
-        mapped. */
-      p -> addr += (CORE_ADDR) LM_ADDR (so);
-      p -> endaddr += (CORE_ADDR) LM_ADDR (so);
+        object's file by the offset to get the address to which the
+        object was actually mapped.  */
+      p -> addr += LM_OFFSET (so);
+      p -> endaddr += LM_OFFSET (so);
       so -> lmend = (CORE_ADDR) max (p -> endaddr, so -> lmend);
-      if (STREQ (p -> sec_ptr -> name, ".text"))
+      if (STREQ (p -> the_bfd_section -> name, ".text"))
        {
          so -> textsection = p;
        }
@@ -251,9 +317,13 @@ first_link_map_member ()
   ldr_module_t mod_id = LDR_NULL_MODULE;
   size_t retsize;
 
-  if (ldr_next_module(inferior_pid, &mod_id) != 0
+  fake_ldr_process = ldr_core_process ();
+  ldr_set_core_reader (ldr_read_memory);
+  ldr_xdetach (fake_ldr_process);
+  if (ldr_xattach (fake_ldr_process) != 0
+      || ldr_next_module(fake_ldr_process, &mod_id) != 0
       || mod_id == LDR_NULL_MODULE
-      || ldr_inq_module(inferior_pid, mod_id,
+      || ldr_inq_module(fake_ldr_process, mod_id,
                        &first_lm.module_info, sizeof(ldr_module_info_t),
                        &retsize) != 0)
     return lm;
@@ -287,12 +357,12 @@ next_link_map_member (so_list_ptr)
   struct link_map *lm = NULL;
   static struct link_map next_lm;
 #ifdef USE_LDR_ROUTINES
-  ldr_module_t mod_id = lm->module_info.lmi_modid;
+  ldr_module_t mod_id = so_list_ptr->lm.module_info.lmi_modid;
   size_t retsize;
 
-  if (ldr_next_module(inferior_pid, &mod_id) != 0
+  if (ldr_next_module(fake_ldr_process, &mod_id) != 0
       || mod_id == LDR_NULL_MODULE
-      || ldr_inq_module(inferior_pid, mod_id,
+      || ldr_inq_module(fake_ldr_process, mod_id,
                        &next_lm.module_info, sizeof(ldr_module_info_t),
                        &retsize) != 0)
     return lm;
@@ -327,10 +397,21 @@ xfer_link_map_member (so_list_ptr, lm)
      struct so_list *so_list_ptr;
      struct link_map *lm;
 {
+  int i;
   so_list_ptr->lm = *lm;
 
-  /* OSF/1 has absolute addresses in shared libraries.  */
-  LM_ADDR (so_list_ptr) = 0;
+  /* OSF/1 shared libraries are pre-linked to particular addresses,
+     but the runtime loader may have to relocate them if the
+     address ranges of the libraries used by the target executable clash,
+     or if the target executable is linked with the -taso option.
+     The offset is the difference between the address where the shared
+     library is mapped and the pre-linked address of the shared library.
+
+     FIXME:  GDB is currently unable to relocate the shared library
+     sections by different offsets. If sections are relocated by
+     different offsets, put out a warning and use the offset of the
+     first section for all remaining sections.  */
+  LM_OFFSET (so_list_ptr) = 0;
 
   /* There is one entry that has no name (for the inferior executable)
      since it is not a shared object. */
@@ -343,12 +424,66 @@ xfer_link_map_member (so_list_ptr, lm)
       if (len > MAX_PATH_SIZE)
        len = MAX_PATH_SIZE;
       strncpy (so_list_ptr->so_name, LM_NAME (so_list_ptr), MAX_PATH_SIZE);
+      so_list_ptr->so_name[MAX_PATH_SIZE - 1] = '\0';
+
+      for (i = 0; i < lm->module_info.lmi_nregion; i++)
+       {
+         ldr_region_info_t region_info;
+         size_t retsize;
+         CORE_ADDR region_offset;
+
+         if (ldr_inq_region (fake_ldr_process, lm->module_info.lmi_modid,
+                             i, &region_info, sizeof (region_info),
+                             &retsize) != 0)
+           break;
+         region_offset = (CORE_ADDR) region_info.lri_mapaddr
+                         - (CORE_ADDR) region_info.lri_vaddr;
+         if (i == 0)
+           LM_OFFSET (so_list_ptr) = region_offset;
+         else if (LM_OFFSET (so_list_ptr) != region_offset)
+           warning ("cannot handle shared library relocation for %s (%s)",
+                    so_list_ptr->so_name, region_info.lri_name);
+       }
 #else
-      if (!target_read_string((CORE_ADDR) LM_NAME (so_list_ptr),
-                             so_list_ptr->so_name, MAX_PATH_SIZE - 1))
-       error ("xfer_link_map_member: Can't read pathname for load map\n");
+      int errcode;
+      char *buffer;
+      target_read_string ((CORE_ADDR) LM_NAME (so_list_ptr), &buffer,
+                         MAX_PATH_SIZE - 1, &errcode);
+      if (errcode != 0)
+       error ("xfer_link_map_member: Can't read pathname for load map: %s\n",
+              safe_strerror (errcode));
+      strncpy (so_list_ptr->so_name, buffer, MAX_PATH_SIZE - 1);
+      free (buffer);
+      so_list_ptr->so_name[MAX_PATH_SIZE - 1] = '\0';
+
+      for (i = 0; i < lm->module_info.region_count; i++)
+       {
+         ldr_region_info_t region_info;
+         CORE_ADDR region_offset;
+
+         if (target_read_memory (lm->module_info.regioninfo_addr
+                                  + i * sizeof (region_info),
+                                 (char *) &region_info,
+                                 sizeof (region_info)) != 0)
+           break;
+         region_offset = region_info.mapaddr - region_info.vaddr;
+         if (i == 0)
+           LM_OFFSET (so_list_ptr) = region_offset;
+         else if (LM_OFFSET (so_list_ptr) != region_offset)
+           {
+             char *region_name;
+             target_read_string (region_info.regionname_addr, &buffer,
+                                 MAX_PATH_SIZE - 1, &errcode);
+             if (errcode == 0)
+               region_name = buffer;
+             else
+               region_name = "??";
+             warning ("cannot handle shared library relocation for %s (%s)",
+                       so_list_ptr->so_name, region_name);
+             free (buffer);
+           }
+       }
 #endif
-      so_list_ptr->so_name[MAX_PATH_SIZE - 1] = 0;
 
       solib_map_sections (so_list_ptr);
     }
@@ -475,9 +610,7 @@ solib_add (arg_string, from_tty, target)
   
   
   /* Add the shared library sections to the section table of the
-     specified target, if any. We have to do this before reading the
-     symbol files as symbol_file_add calls reinit_frame_cache and
-     creating a new frame might access memory in the shared library.  */
+     specified target, if any.  */
   if (target)
     {
       /* Count how many new section_table entries there are.  */
@@ -493,6 +626,13 @@ solib_add (arg_string, from_tty, target)
       
       if (count)
        {
+         int update_coreops;
+
+         /* We must update the to_sections field in the core_ops structure
+            here, otherwise we dereference a potential dangling pointer
+            for each call to target_read/write_memory within this routine.  */
+         update_coreops = core_ops.to_sections == target->to_sections;
+            
          /* Reallocate the target's section table including the new size.  */
          if (target -> to_sections)
            {
@@ -509,6 +649,14 @@ solib_add (arg_string, from_tty, target)
            }
          target -> to_sections_end = target -> to_sections + (count + old);
          
+         /* Update the to_sections field in the core_ops structure
+            if needed.  */
+         if (update_coreops)
+           {
+             core_ops.to_sections = target->to_sections;
+             core_ops.to_sections_end = target->to_sections_end;
+           }
+
          /* Add these section table entries to the target's table.  */
          while ((so = find_solib (so)) != NULL)
            {
@@ -548,6 +696,11 @@ solib_add (arg_string, from_tty, target)
            }
        }
     }
+
+  /* Getting new symbols may change our opinion about what is
+     frameless.  */
+  if (so_last)
+    reinit_frame_cache ();
 }
 
 /*
@@ -617,7 +770,7 @@ GLOBAL FUNCTION
 
 SYNOPSIS
 
-       int solib_address (CORE_ADDR address)
+       char *solib_address (CORE_ADDR address)
 
 DESCRIPTION
 
@@ -633,7 +786,7 @@ DESCRIPTION
        mapped in.
  */
 
-int
+char *
 solib_address (address)
      CORE_ADDR address;
 {
@@ -645,9 +798,7 @@ solib_address (address)
        {
          if ((address >= (CORE_ADDR) so -> textsection -> addr) &&
              (address < (CORE_ADDR) so -> textsection -> endaddr))
-           {
-             return (1);
-           }
+           return (so->so_name);
        }
     }
   return (0);
@@ -670,7 +821,9 @@ clear_solib()
       if (so_list_head -> abfd)
        {
          bfd_filename = bfd_get_filename (so_list_head -> abfd);
-         bfd_close (so_list_head -> abfd);
+         if (!bfd_close (so_list_head -> abfd))
+           warning ("cannot close \"%s\": %s",
+                    bfd_filename, bfd_errmsg (bfd_get_error ()));
        }
       else
        /* This happens for the executable on SVR4.  */
@@ -726,7 +879,9 @@ solib_create_inferior_hook()
 
   /* Nothing to do for statically bound executables.  */
 
-  if (symfile_objfile == 0 || symfile_objfile->ei.entry_file_lowpc == stop_pc)
+  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
@@ -744,13 +899,14 @@ solib_create_inferior_hook()
     }
   while (stop_signal != TARGET_SIGNAL_TRAP);
 
-  /*  solib_add will call reinit_frame_cache via symbol_file_add.
+  /*  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.
-      Resetting stop_soon_quietly after symbol loading suppresses
-      the warning.  */
-  solib_add ((char *) 0, 0, (struct target_ops *) 0);
+      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;
 }
 
@@ -781,9 +937,19 @@ int from_tty;
 void
 _initialize_solib()
 {
-  
   add_com ("sharedlibrary", class_files, sharedlibrary_command,
           "Load shared object library symbols for files matching REGEXP.");
   add_info ("sharedlibrary", info_sharedlibrary_command, 
            "Status of loaded shared object libraries.");
+
+  add_show_from_set
+    (add_set_cmd ("auto-solib-add", class_support, var_zinteger,
+                 (char *) &auto_solib_add,
+                 "Set autoloading of shared library symbols.\n\
+If nonzero, symbols from all shared object libraries will be loaded\n\
+automatically when the inferior begins execution or when the dynamic linker\n\
+informs gdb that a new library has been loaded.  Otherwise, symbols\n\
+must be loaded manually, using `sharedlibrary'.",
+                 &setlist),
+     &showlist);
 }
This page took 0.0278 seconds and 4 git commands to generate.