* procfs.c (dbx_link_bpt_addr): New static global variable.
authorJoel Brobecker <brobecker@gnat.com>
Fri, 27 Aug 2004 13:37:42 +0000 (13:37 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Fri, 27 Aug 2004 13:37:42 +0000 (13:37 +0000)
        (dbx_link_shadow_contents): New static global variable.
        (procfs_wait, case <PR_SYSEXIT>): Handle syssgi events.
        (procfs_wait, case <FLTBPT>): Remove the __dbx_link brekapoint
        if we just hit it.
        (procfs_init_inferior): Enable syssgi() syscall trace if appropriate.
        Reset dbx_link_bpt_addr as the address of __dbx_link() may change
        from run to run.
        (procfs_create_inferior): Remove syssgi syscall-exit notifications
        after the inferior has been forked.
        (remove_dbx_link_breakpoint): New function.
        (dbx_link_addr): New function.
        (insert_dbx_link_bpt_in_file): New function.
        (insert_dbx_link_bpt_in_region): New function.
        (insert_dbx_link_breakpoint): New function.
        (proc_trace_syscalls_1): New function, extracted from
        proc_trace_syscalls.
        (proc_trace_syscalls): Replace extract code by call to
        proc_trace_syscalls_1.
        * solib-irix.c (disable_break): Remove stop_pc assertion, as it
        is no longer valid.

gdb/ChangeLog
gdb/procfs.c
gdb/solib-irix.c

index 7decaadd6f21add9c60bb59f5f35479d57645a34..0ac0540bcec19a66e46cd9dbc8d883cb71767d62 100644 (file)
@@ -1,3 +1,27 @@
+2004-08-27  Joel Brobecker  <brobecker@gnat.com>
+
+       * procfs.c (dbx_link_bpt_addr): New static global variable.
+       (dbx_link_shadow_contents): New static global variable.
+       (procfs_wait, case <PR_SYSEXIT>): Handle syssgi events.
+       (procfs_wait, case <FLTBPT>): Remove the __dbx_link brekapoint
+       if we just hit it.
+       (procfs_init_inferior): Enable syssgi() syscall trace if appropriate.
+       Reset dbx_link_bpt_addr as the address of __dbx_link() may change
+       from run to run.
+       (procfs_create_inferior): Remove syssgi syscall-exit notifications
+       after the inferior has been forked.
+       (remove_dbx_link_breakpoint): New function.
+       (dbx_link_addr): New function.
+       (insert_dbx_link_bpt_in_file): New function.
+       (insert_dbx_link_bpt_in_region): New function.
+       (insert_dbx_link_breakpoint): New function.
+       (proc_trace_syscalls_1): New function, extracted from
+       proc_trace_syscalls.
+       (proc_trace_syscalls): Replace extract code by call to
+       proc_trace_syscalls_1.
+       * solib-irix.c (disable_break): Remove stop_pc assertion, as it
+       is no longer valid.
+
 2004-08-25  Jim Blandy  <jimb@redhat.com>
 
        * gdbtypes.h (TYPE_CODE_ARRAY): Doc fix.
index 3ac970240287ee313508d8a7fe0d0f268e940d2c..0a1f1528b3abfb4df13314f033ae8c265fb22d85 100644 (file)
@@ -3382,6 +3382,17 @@ proc_iterate_over_threads (procinfo *pi,
 static ptid_t do_attach (ptid_t ptid);
 static void do_detach (int signo);
 static int register_gdb_signals (procinfo *, gdb_sigset_t *);
+static void proc_trace_syscalls_1 (procinfo *pi, int syscallnum,
+                                   int entry_or_exit, int mode, int from_tty);
+static int insert_dbx_link_breakpoint (procinfo *pi);
+static void remove_dbx_link_breakpoint (void);
+
+/* On mips-irix, we need to insert a breakpoint at __dbx_link during
+   the startup phase.  The following two variables are used to record
+   the address of the breakpoint, and the code that was replaced by
+   a breakpoint.  */
+static int dbx_link_bpt_addr = 0;
+static char dbx_link_shadow_contents[BREAKPOINT_MAX];
 
 /*
  * Function: procfs_debug_inferior
@@ -4070,6 +4081,22 @@ wait_again:
                       address. */
                    wstat = (SIGTRAP << 8) | 0177;
                  }
+#ifdef SYS_syssgi
+                else if (what == SYS_syssgi)
+                  {
+                    /* see if we can break on dbx_link().  If yes, then
+                       we no longer need the SYS_syssgi notifications.  */
+                    if (insert_dbx_link_breakpoint (pi))
+                      proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT,
+                                             FLAG_RESET, 0);
+
+                    /* This is an internal event and should be transparent
+                       to wfi, so resume the execution and wait again.  See
+                       comment in procfs_init_inferior() for more details.  */
+                    target_resume (ptid, 0, TARGET_SIGNAL_0);
+                    goto wait_again;
+                  }
+#endif
                else if (syscall_is_lwp_create (pi, what))
                  {
                    /*
@@ -4196,6 +4223,13 @@ wait_again:
 #if (FLTTRACE != FLTBPT)       /* avoid "duplicate case" error */
                case FLTTRACE:
 #endif
+                  /* If we hit our __dbx_link() internal breakpoint,
+                     then remove it.  See comments in procfs_init_inferior()
+                     for more details.  */
+                  if (dbx_link_bpt_addr != 0
+                      && dbx_link_bpt_addr == read_pc ())
+                    remove_dbx_link_breakpoint ();
+
                  wstat = (SIGTRAP << 8) | 0177;
                  break;
                case FLTSTACK:
@@ -4847,6 +4881,32 @@ procfs_init_inferior (int pid)
   /* Typically two, one trap to exec the shell, one to exec the
      program being debugged.  Defined by "inferior.h".  */
   startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
+
+#ifdef SYS_syssgi
+  /* On mips-irix, we need to stop the inferior early enough during
+     the startup phase in order to be able to load the shared library
+     symbols and insert the breakpoints that are located in these shared
+     libraries.  Stopping at the program entry point is not good enough
+     because the -init code is executed before the execution reaches
+     that point.
+
+     So what we need to do is to insert a breakpoint in the runtime
+     loader (rld), more precisely in __dbx_link().  This procedure is
+     called by rld once all shared libraries have been mapped, but before
+     the -init code is executed. Unfortuantely, this is not straightforward,
+     as rld is not part of the executable we are running, and thus we need
+     the inferior to run until rld itself has been mapped in memory.
+     
+     For this, we trace all syssgi() syscall exit events.  Each time
+     we detect such an event, we iterate over each text memory maps,
+     get its associated fd, and scan the symbol table for __dbx_link().
+     When found, we know that rld has been mapped, and that we can insert
+     the breakpoint at the symbol address.  Once the dbx_link() breakpoint
+     has been inserted, the syssgi() notifications are no longer necessary,
+     so they should be canceled.  */
+  proc_trace_syscalls_1 (pi, SYS_syssgi, PR_SYSEXIT, FLAG_SET, 0);
+  dbx_link_bpt_addr = 0;
+#endif
 }
 
 /*
@@ -5053,6 +5113,16 @@ procfs_create_inferior (char *exec_file, char *allargs, char **env,
   fork_inferior (exec_file, allargs, env, procfs_set_exec_trap,
                 procfs_init_inferior, NULL, shell_file);
 
+#ifdef SYS_syssgi
+  /* Make sure to cancel the syssgi() syscall-exit notifications.  
+     They should normally have been removed by now, but they may still
+     be activated if the inferior doesn't use shared libraries, or if
+     we didn't locate __dbx_link, or if we never stopped in __dbx_link.
+     See procfs_init_inferior() for more details.  */
+  proc_trace_syscalls_1 (find_procinfo_or_die (PIDGET (inferior_ptid), 0),
+                         SYS_syssgi, PR_SYSEXIT, FLAG_RESET, 0);
+#endif
+  
   /* We are at the first instruction we care about.  */
   /* Pedal to the metal... */
 
@@ -5515,6 +5585,131 @@ proc_find_memory_regions (int (*func) (CORE_ADDR,
                                find_memory_regions_callback);
 }
 
+/* Remove the breakpoint that we inserted in __dbx_link().
+   Does nothing if the breakpoint hasn't been inserted or has already
+   been removed.  */
+
+static void
+remove_dbx_link_breakpoint (void)
+{
+  if (dbx_link_bpt_addr == 0)
+    return;
+
+  if (memory_remove_breakpoint (dbx_link_bpt_addr,
+                                dbx_link_shadow_contents) != 0)
+    warning ("Unable to remove __dbx_link breakpoint.");
+
+  dbx_link_bpt_addr = 0;
+}
+
+/* Return the address of the __dbx_link() function in the file
+   refernced by ABFD by scanning its symbol table.  Return 0 if
+   the symbol was not found.  */
+
+static CORE_ADDR
+dbx_link_addr (bfd *abfd)
+{
+  long storage_needed;
+  asymbol **symbol_table;
+  long number_of_symbols;
+  long i;
+
+  storage_needed = bfd_get_symtab_upper_bound (abfd);
+  if (storage_needed <= 0)
+    return 0;
+
+  symbol_table = (asymbol **) xmalloc (storage_needed);
+  make_cleanup (xfree, symbol_table);
+
+  number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+  for (i = 0; i < number_of_symbols; i++)
+    {
+      asymbol *sym = symbol_table[i];
+
+      if ((sym->flags & BSF_GLOBAL)
+          && sym->name != NULL && strcmp (sym->name, "__dbx_link") == 0)
+        return (sym->value + sym->section->vma);
+    }
+
+  /* Symbol not found, return NULL.  */
+  return 0;
+}
+
+/* Search the symbol table of the file referenced by FD for a symbol
+   named __dbx_link(). If found, then insert a breakpoint at this location,
+   and return nonzero.  Return zero otherwise.  */
+
+static int
+insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored)
+{
+  bfd *abfd;
+  long storage_needed;
+  CORE_ADDR sym_addr;
+
+  abfd = bfd_fdopenr ("unamed", 0, fd);
+  if (abfd == NULL)
+    {
+      warning ("Failed to create a bfd: %s.\n", bfd_errmsg (bfd_get_error ()));
+      return 0;
+    }
+
+  if (!bfd_check_format (abfd, bfd_object))
+    {
+      /* Not the correct format, so we can not possibly find the dbx_link
+         symbol in it.  */
+      bfd_close (abfd);
+      return 0;
+    }
+
+  sym_addr = dbx_link_addr (abfd);
+  if (sym_addr != 0)
+    {
+      /* Insert the breakpoint.  */
+      dbx_link_bpt_addr = sym_addr;
+      if (target_insert_breakpoint (sym_addr, dbx_link_shadow_contents) != 0)
+        {
+          warning ("Failed to insert dbx_link breakpoint.");
+          bfd_close (abfd);
+          return 0;
+        }
+      bfd_close (abfd);
+      return 1;
+    }
+
+  bfd_close (abfd);
+  return 0;
+} 
+
+/* If the given memory region MAP contains a symbol named __dbx_link,
+   insert a breakpoint at this location and return nonzero.  Return
+   zero otherwise.  */
+
+static int
+insert_dbx_link_bpt_in_region (struct prmap *map,
+                               int (*child_func) (),
+                               void *data)
+{     
+  procinfo *pi = (procinfo *) data;
+        
+  /* We know the symbol we're looking for is in a text region, so
+     only look for it if the region is a text one.  */
+  if (map->pr_mflags & MA_EXEC)
+    return solib_mappings_callback (map, insert_dbx_link_bpt_in_file, pi);
+  return 0;
+}           
+
+/* Search all memory regions for a symbol named __dbx_link.  If found,
+   insert a breakpoint at its location, and return nonzero.  Return zero
+   otherwise.  */
+
+static int
+insert_dbx_link_breakpoint (procinfo *pi)
+{
+  return iterate_over_mappings (pi, NULL, pi, insert_dbx_link_bpt_in_region);
+}
+
 /*
  * Function: mappingflags
  *
@@ -5703,12 +5898,50 @@ info_proc_cmd (char *args, int from_tty)
   do_cleanups (old_chain);
 }
 
+/* Modify the status of the system call identified by SYSCALLNUM in
+   the set of syscalls that are currently traced/debugged.
+
+   If ENTRY_OR_EXIT is set to PR_SYSENTRY, then the entry syscalls set
+   will be updated. Otherwise, the exit syscalls set will be updated.
+
+   If MODE is FLAG_SET, then traces will be enabled. Otherwise, they
+   will be disabled.  */
+
+static void
+proc_trace_syscalls_1 (procinfo *pi, int syscallnum, int entry_or_exit,
+                      int mode, int from_tty)
+{
+  sysset_t *sysset;
+  
+  if (entry_or_exit == PR_SYSENTRY)
+    sysset = proc_get_traced_sysentry (pi, NULL);
+  else
+    sysset = proc_get_traced_sysexit (pi, NULL);
+
+  if (sysset == NULL)
+    proc_error (pi, "proc-trace, get_traced_sysset", __LINE__);
+
+  if (mode == FLAG_SET)
+    gdb_praddsysset (sysset, syscallnum);
+  else
+    gdb_prdelsysset (sysset, syscallnum);
+
+  if (entry_or_exit == PR_SYSENTRY)
+    {
+      if (!proc_set_traced_sysentry (pi, sysset))
+        proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__);
+    }
+  else
+    {
+      if (!proc_set_traced_sysexit (pi, sysset))
+        proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__);
+    }
+}
+
 static void
 proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode)
 {
   procinfo *pi;
-  sysset_t *sysset;
-  int       syscallnum = 0;
 
   if (PIDGET (inferior_ptid) <= 0)
     error ("you must be debugging a process to use this command.");
@@ -5719,30 +5952,9 @@ proc_trace_syscalls (char *args, int from_tty, int entry_or_exit, int mode)
   pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0);
   if (isdigit (args[0]))
     {
-      syscallnum = atoi (args);
-      if (entry_or_exit == PR_SYSENTRY)
-       sysset = proc_get_traced_sysentry (pi, NULL);
-      else
-       sysset = proc_get_traced_sysexit (pi, NULL);
-
-      if (sysset == NULL)
-       proc_error (pi, "proc-trace, get_traced_sysset", __LINE__);
-
-      if (mode == FLAG_SET)
-       gdb_praddsysset (sysset, syscallnum);
-      else
-       gdb_prdelsysset (sysset, syscallnum);
+      const int syscallnum = atoi (args);
 
-      if (entry_or_exit == PR_SYSENTRY)
-       {
-         if (!proc_set_traced_sysentry (pi, sysset))
-           proc_error (pi, "proc-trace, set_traced_sysentry", __LINE__);
-       }
-      else
-       {
-         if (!proc_set_traced_sysexit (pi, sysset))
-           proc_error (pi, "proc-trace, set_traced_sysexit", __LINE__);
-       }
+      proc_trace_syscalls_1 (pi, syscallnum, entry_or_exit, mode, from_tty);
     }
 }
 
index aaf8338bb25b791bb365b847c0e24426c65f7952..5795ecaf0c17195377ea05478dbae1a8be7ec134 100644 (file)
@@ -324,15 +324,11 @@ disable_break (void)
       status = 0;
     }
 
-  /* For the SVR4 version, we always know the breakpoint address.  For the
-     SunOS version we don't know it until the above code is executed.
-     Grumble if we are stopped anywhere besides the breakpoint address. */
-
-  if (stop_pc != breakpoint_addr)
-    {
-      warning
-       ("stopped at unknown breakpoint while handling shared libraries");
-    }
+  /* Note that it is possible that we have stopped at a location that
+     is different from the location where we inserted our breakpoint.
+     On mips-irix, we can actually land in __dbx_init(), so we should
+     not check the PC against our breakpoint address here.  See procfs.c
+     for more details.  */
 
   return (status);
 }