> The result has been bootstrapped by Eric (thanks for this and debugging
> why a first version caused some regressions on Solaris 8) and myself on
> Solaris 8, 9, 10 and 11, and I've performed quite a bit of software
> archaeology (i.e. stared at old libc.so.1 and libthread.so.1 patches) to
> make sure noting got missed in the process.

All EH-related tests fail with a recent upgrade on Solaris 10.  Interestingly, 
the old implementation keeps working with the upgrade.  It seems that the 
__sighndlr case has been over-simplified:

  /* Look for the __sighndlr pattern.  */
  else if (    *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0]
            && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1]
            && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2]
            && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3]
            && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4]
            && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5]
            && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] )
    {
      /* We have observed different calling frames among different
         versions of the operating system, so that we need to
         discriminate using the upper frame.  We look for the return
         address of the caller frame (there is an offset of 15 words
         between the frame address and the place where this return
         address is stored) in order to do some more pattern matching.  */
      unsigned int cuh_pattern
        = *(unsigned int *)(*(unsigned int *)(this_cfa + 15*4) - 4);

      if (cuh_pattern == 0xd407a04c)
        {
          /* This matches the call_user_handler pattern for Solaris 10.
             There are 2 cases so we look for the return address of the
             caller's caller frame in order to do more pattern matching.  */
          unsigned int sah_pattern
            = *(unsigned int *)(*(unsigned int *)(this_cfa + 96 + 15*4) - 4);

          if (sah_pattern == 0x92100019)
            /* This is the same setup as for Solaris 9, see below.  */
            regs_off = 96 + 96 + 96 + 160;
          else
            /* We need to move up three frames (the kernel frame, the
               call_user_handler frame, the __sighndlr frame).  Two of them
               have the minimum stack frame size (kernel and __sighndlr
               frames) of 96 bytes, and there is another with a stack frame
               of 160 bytes (the call_user_handler frame).  The ucontext_t
               structure is after this offset.  */
            regs_off = 96 + 96 + 160;
        }
      else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b)
        /* This matches the call_user_handler pattern for Solaris 9 and
           for Solaris 8 running inside Solaris Containers respectively.
           We need to move up four frames (the kernel frame, the signal
           frame, the call_user_handler frame, the __sighndlr frame).
           Three of them have the minimum stack frame size (kernel,
           signal, and __sighndlr frames) of 96 bytes, and there is
           another with a stack frame of 160 bytes (the call_user_handler
           frame).  The ucontext_t structure is after this offset.  */
        regs_off = 96 + 96 + 96 + 160;
      else
        /* We need to move up three frames (the kernel frame, the
           sigacthandler frame, and the __sighndlr frame).  Two of them
           have the minimum stack frame size (kernel and __sighndlr
           frames) of 96 bytes, and there is another with a stack frame
           of 216 bytes (the sigacthandler frame).  The ucontext_t 
           structure is after this offset.  */
        regs_off = 96 + 96 + 216;
    }

to

  if(/* Solaris 8+ - multi-threaded
       ----------------------------
       <__sighndlr>:    save  %sp, -96, %sp
       <__sighndlr+4>:  mov  %i0, %o0
       <__sighndlr+8>:  mov  %i1, %o1
       <__sighndlr+12>: call  %i3
       <__sighndlr+16>: mov  %i2, %o2
       <__sighndlr+20>: ret             <--- PC
       <__sighndlr+24>: restore  */
        pc[-5] == 0x9de3bfa0
     && pc[-4] == 0x90100018
     && pc[-3] == 0x92100019
     && pc[-2] == 0x9fc6c000
     && pc[-1] == 0x9410001a
     && pc[ 0] == 0x81c7e008
     && pc[ 1] == 0x81e80000)
    {
      if (/* Solaris 8 /usr/lib/libthread.so.1
            ----------------------------------
            <sigacthandler+1796>:     mov  %i0, %o0  */
          savpc[-1] == 0x90100018)
        {
          /* We need to move up two frames:

                <signal handler>        <-- context->cfa
                __sighndlr
                sigacthandler
                <kernel>
          */
          *nframes = 2;
        }
      else /* Solaris 8 /usr/lib/lwp/libthread.so.1, Solaris 9+
             --------------------------------------------------  */
        {
          /* We need to move up three frames:

                <signal handler>        <-- context->cfa
                __sighndlr
                call_user_handler
                sigacthandler
                <kernel>
          */
          *nframes = 3;
        }
      return 1;
    }

In particular, the old fallback case (2 frames) has been changed (to 3 frames), 
The upgrade seems to have reverted to 2 frames because of a sibling call.

-- 
Eric Botcazou

Reply via email to