From: haw30@ras.amdahl.COM (Henry A Worth)
Newsgroups: gnu.gdb.bug
Subject: Solaris shared object bug (gdb-4.7)
Date: 26 Jan 1993 22:14:04 -0500
Organization: GNUs Not Usenet
Distribution: gnu

   > From: jsc@sun.com (John Cooper)
   > Newsgroups: gnu.gdb.bug
   > Subject: Solaris problem (again)
   > 
   > Could one of the gdb developers please have the courtesy to at least
   > respond to my post. If gdb on Solaris doesn't work with shared
   > libraries, just say so! If you're too busy to look into the issue,
   > that's ok too, but please at least acknowledge the problem.
   > 

   I'd like to see a response as well (in general, just what is the status
of Solaris ports, some sort of concise status for each port would be a nice 
addition to the distributions, trying to infer features and stability of a
port from the Changelogs, NEWS,... is not easy). I've been using GCC2.3.3 
and GDB-4.7 under Solaris2.0/2.1 on a Sparc with shared objects with some 
mixed success. Attaching to a running process works (main excpetion is
if the process is sleeping, this seems to be fixed in Solaris2.1). But 
running a process from gdb as below will fail if you breakpoint at main, 
or anywhere else, with a segmentation or illegal instruction exception.

   > 
   > Whenever I step over any function in a shared library (in this case,
   > printf() in libc.so), gdb gives the following segmentation fault:
   > 
   > gdb-4.7/gdb/gdb hello
   > GDB is free software and you are welcome to distribute copies of it
   >  under certain conditions; type "show copying" to see the conditions.
   > There is absolutely no warranty for GDB; type "show warranty" for details.
   > GDB 4.7, Copyright 1992 Free Software Foundation, Inc...
   > (gdb) b main
   > Breakpoint 1 at 0x10778: file hello.c, line 8.
   > (gdb) r
   > Starting program: /saxon/jsc/hello 

     I get a number of sigtraps stops at this point. I assume you
edited them out, but they are an important clue to the bug.

   > 
   > Breakpoint 1, main (argc=1, argv=0xeffff9cc) at hello.c:8
   > 8	    a = 2;
   > (gdb) n
   > 9	    printf("Hello World\n");
   > (gdb) n
   > 0x208d0 in __DTOR_END__ ()
   > (gdb) 
   > Current function has no line number information.
   > Single stepping until function exit.
   > 

     gcc2.3.3 seems to have problems generating stabs for Solaris,
the debugger occasionally gets confused as to where it is, even with
un-optimized code. Someone posted a bug report on this. 

   > Program received signal 11, Segmentation fault
   > 0xef7d906c in _fp_current_direction ()
   > (gdb)
   > 

     Part of the  problem is caused by the handling of sigtraps generated 
by SVR4 ld.so during the start-up mapping phase, there are various comments 
in solib.c that this is a problem area that needs to be reworked someday.
The SVR4 "breakpoint at main" workaround does not work in Solaris as the 
contents of main have not been loaded at the time enable_breaks() is 
executed. The contents of main are not loaded until the last 
sigtrap. The result is that the attempt to set a "mapping-complete" 
breakpoint fails. Also, with all the mapping sigtraps that occur, the 
mapping loop in solib_create_inferior_hook() is exited too soon, resulting 
in user breakpoints being set and cleared incorrectly. I've included a 
work-around hack below, with the emphasis on HACK, there are no guarantees,
but so far this has worked for me (also included is a patch to an earlier
reported bug covering the possibility of a nil testsection pointer in object
files containing only data).


------------------------------ start of patch -----------------------------
*** ../gdb/solib.c	Fri Jul  3 20:21:41 1992
--- solib.c	Mon Jan 25 15:38:53 1993
***************
*** 670,678 ****
       char *arg;
  {
    register struct so_list *so = (struct so_list *) arg;	/* catch_errs bogon */
    
    so -> objfile = symbol_file_add (so -> so_name, so -> from_tty,
! 				   (unsigned int) so -> textsection -> addr,
  				   0, 0, 0);
    return (1);
  }
--- 670,679 ----
       char *arg;
  {
    register struct so_list *so = (struct so_list *) arg;	/* catch_errs bogon */
+   register struct section_table *txt = so -> textsection; /* may be nil!!!  */
    
    so -> objfile = symbol_file_add (so -> so_name, so -> from_tty,
! 				   (unsigned int) (txt ? txt -> addr : 0),
  				   0, 0, 0);
    return (1);
  }
***************
*** 1128,1134 ****
  void 
  solib_create_inferior_hook()
  {
!   
    if ((debug_base = locate_base ()) == 0)
      {
        /* Can't find the symbol or the executable is statically linked. */
--- 1129,1137 ----
  void 
  solib_create_inferior_hook()
  {
!   CORE_ADDR first_trap_pc = 0;
!   CORE_ADDR second_trap_pc = 0;
!  
    if ((debug_base = locate_base ()) == 0)
      {
        /* Can't find the symbol or the executable is statically linked. */
***************
*** 1135,1145 ****
--- 1138,1152 ----
        return;
      }
  
+ #ifdef SUN4_SOL2_SOLIB_HACK
+   breakpoint_addr = 0;
+ #else 
    if (!enable_break ())
      {
        warning ("shared library handler failed to enable breakpoint");
        return;
      }
+ #endif /* SUN4_SOL2_SOLIB_HACK */
  
    /* Now run the target.  It will eventually hit the breakpoint, at
       which point all of the libraries will have been mapped in and we
***************
*** 1151,1167 ****
    stop_signal = 0;
    do
      {
        target_resume (0, stop_signal);
        wait_for_inferior ();
      }
    while (stop_signal != SIGTRAP);
!   stop_soon_quietly = 0;
!   
    /* We are now either at the "mapping complete" breakpoint (or somewhere
       else, a condition we aren't prepared to deal with anyway), so adjust
       the PC as necessary after a breakpoint, disable the breakpoint, and
       add any shared libraries that were mapped in. */
! 
    if (DECR_PC_AFTER_BREAK)
      {
        stop_pc -= DECR_PC_AFTER_BREAK;
--- 1158,1244 ----
    stop_signal = 0;
    do
      {
+ 
+ #ifdef SUN4_SOL2_SOLIB_HACK
+       if( stop_signal == SIGTRAP )
+         {
+           if ( stop_pc == breakpoint_addr )
+             {
+               /* we've finally reached main */
+               break;
+             }
+           /* 
+            * The SVR4 "breakpoint at main" hack doesn't work for SOLARIS2,
+            * when the enable_break() is called, main has not yet been loaded, 
+            * also multiple sigtraps occur during shared object mapping, 
+            * so we exit this loop too soon and the breakpoint at main is lost.
+            * Additionally, if the user attempted to set any breakpoints, 
+            * the incomplete loading state when this loop is exited 
+            * results in the wrong shadow contents being saved and any
+            * attempt to continue typically results in segmentation or
+            * illegal instruction exceptions.
+            *
+            * This hack tries to determine when the last mapping sigtrap has 
+            * been reached, at which point we can set the breakpoint at main.
+            * When the breakpoint at main is reached we exit the loop. 
+            *
+            * Determining which sigtrap is the last mapping sigtrap is
+            * problematic, this hack is based upon the observation that the
+            * last two mapping sigtraps have a different address than the 
+            * rest. When the second of this last pair is reached the
+            * the breakpoint at main is set. The empahsis is on HACK
+            * and there are no guarantees that this will work in all
+            * situations.
+            *
+            * Is there some data structure that indicates we have 
+            * finished mapping in shared objects (some PIOC call?)?
+            * If so, that would be a much preferable method. 
+            */ 
+ 
+           if (first_trap_pc == 0)
+             first_trap_pc = stop_pc;
+           else
+             {
+               if (first_trap_pc != stop_pc)
+                 {
+                   if (second_trap_pc == 0 )
+                     second_trap_pc = stop_pc;
+                   else 
+                     {
+                       /* program space is loaded and writable, we hope! */
+                       if (!enable_break ())
+                         {
+                           warning ("shared library handler failed to enable breakpoint");
+                           return;
+                         }
+                     }
+                 }
+             }
+           stop_signal = 0;
+         }
+ #endif  /* SUN4_SOL2_SOLIB_HACK */ 
+ 
        target_resume (0, stop_signal);
        wait_for_inferior ();
      }
+ 
+ #ifdef SUN4_SOL2_SOLIB_HACK 
+ 
+   /* continue until ld.so finishes mapping all shared objects */
+ 
+   while ( 1 );
+ 
+ #else 
+ 
    while (stop_signal != SIGTRAP);
! 
! #endif  /* SUN4_SOL2_SOLIB_HACK */ 
!  
    /* We are now either at the "mapping complete" breakpoint (or somewhere
       else, a condition we aren't prepared to deal with anyway), so adjust
       the PC as necessary after a breakpoint, disable the breakpoint, and
       add any shared libraries that were mapped in. */
!  
    if (DECR_PC_AFTER_BREAK)
      {
        stop_pc -= DECR_PC_AFTER_BREAK;
***************
*** 1168,1177 ****
--- 1245,1259 ----
        write_register (PC_REGNUM, stop_pc);
      }
  
+ 
+   stop_soon_quietly = 0;
+  
+ #ifdef BKPT_AT_MAIN
    if (!disable_break ())
      {
        warning ("shared library handler failed to disable breakpoint");
      }
+ #endif  /*  BKPT_AT_MAIN */ 
  
    solib_add ((char *) 0, 0, (struct target_ops *) 0);
  }


*** ../gdb/tm-sun4sol2.h	Thu Oct 22 10:51:08 1992
--- tm-sun4sol2.h	Thu Jan 21 14:30:51 1993
***************
*** 64,67 ****
--- 64,73 ----
  get_longjmp_target PARAMS ((CORE_ADDR *));
  
  #define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
+ 
  #endif  /* 0 */
+ 
+ /* Solaris 2 shared object startup is not yet handled correctly.
+    this macro enables a work-around hack. */
+ 
+ #define SUN4_SOL2_SOLIB_HACK
----------------------- end of patch ---------------------------------