[hpux] problem during unwinding from bizarre code

Joel Brobecker brobecker@adacore.com
Fri Dec 10 14:50:00 GMT 2004

Hello Randolph,

Using the Ada code copied at the end of this message, and compiled with
the command:

        % gnatmake -g task_switch

The following transcript shows that we are seeing a failure when
unwinding from pthread_mutex_unlock():

    (gdb) b task_switch.adb:43
    Breakpoint 1 at 0xa684: file task_switch.adb, line 43.
    (gdb) run
    Starting program: /[...]/task_switch 
    [New thread 2 (system thread 19159)]
    [New thread 3 (system thread 19160)]
    [Switching to thread 3 (system thread 19160)]
    Breakpoint 1, task_switch.break_me () at task_switch.adb:43
    43         end Break_Me;
    (gdb) thread 1
    [Switching to thread 1 (system thread 11738)]#0  0x7afff760 in __kwakeup ()
       from /usr/lib/libc.2
    (gdb) bt
    #0  0x7afff760 in __kwakeup () from /usr/lib/libc.2
    #1  0x7aee5fe8 in __spin_unlock () from /usr/lib/libpthread.1
    #2  0x7aee45a8 in pthread_mutex_unlock () from /usr/lib/libpthread.1
    #3  0x7aee45a8 in pthread_mutex_unlock () from /usr/lib/libpthread.1
    Previous frame identical to this frame (corrupt stack?)

We failed during the unwind from frame 2.  The unwind record for 0x7aee45a8
(frame 2) is:

$2 = {region_start = 0x7aee4594, region_end = 0x7aee45b0, Cannot_unwind = 0x0, 
  Millicode = 0x0, Millicode_save_sr0 = 0x0, Region_description = 0x3, 
  reserved1 = 0x0, Entry_SR = 0x0, Entry_FR = 0x0, Entry_GR = 0x1, 
  Args_stored = 0x1, Variable_Frame = 0x0, Separate_Package_Body = 0x0, 
  Frame_Extension_Millicode = 0x0, Stack_Overflow_Check = 0x0, 
  Two_Instruction_SP_Increment = 0x0, Ada_Region = 0x0, cxx_info = 0x0, 
  cxx_try_catch = 0x0, sched_entry_seq = 0x0, reserved2 = 0x1, Save_SP = 0x0, 
  Save_RP = 0x1, Save_MRP_in_frame = 0x0, extn_ptr_defined = 0x0, 
  Cleanup_defined = 0x0, MPE_XL_interrupt_marker = 0x0, 
  HP_UX_interrupt_marker = 0x0, Large_frame = 0x0, Pseudo_SP_Set = 0x0, 
  reserved4 = 0x1, Total_frame_size = 0x10, stub_unwind = {stub_type = 0x0, 
    padding = 0x0}}

When you look at the code corresponding to that region, you find:

    0x7aee4594 <pthread_mutex_unlock+1084>: ldw 3c(sr0,r3),ret0
    0x7aee4598 <pthread_mutex_unlock+1088>: ldo -1(ret0),r31
    0x7aee459c <pthread_mutex_unlock+1092>: stw r31,3c(sr0,r3)
    0x7aee45a0 <pthread_mutex_unlock+1096>: b,l 0x7aee5fa8 <__spin_unlock>,rp
    0x7aee45a4 <pthread_mutex_unlock+1100>: ldo 8(r3),r26
    0x7aee45a8 <pthread_mutex_unlock+1104>: ldw -20(sr0,sp),r19
    0x7aee45ac <pthread_mutex_unlock+1108>: 
        movb,tr r0,ret0,0x7aee4518 <pthread_mutex_unlock+960>
    0x7aee45b0 <pthread_mutex_unlock+1112>: ldw -94(sr0,sp),rp

It looks like one of these cases where we have a function for which
no symbol has been defined. But at the same time, the code above does
not very much look like a function to me, no?

Looking a bit closer, a collegue and myself found that the code range
that GDB thinks is pthread_mutex_unlock has several unwind records.
For instance, it starts with:

    (gdb) maintenance print unwind &pthread_mutex_unlock
    unwind_table_entry (0x401db134):
            region_start = 0x7aee4158 <pthread_mutex_unlock>
            region_end = 0x7aee42a0 <pthread_mutex_unlock+328>
            flags = Args_stored Save_RP
            Region_description = 0x0
            Entry_FR = 0x0
            Entry_GR = 0x2
            Total_frame_size = 0x8

And the region end code is:

    0x7aee428c <pthread_mutex_unlock+308>:  ldo 0(r3),r26
    0x7aee4290 <pthread_mutex_unlock+312>:  ldw -20(,sp),r19
    0x7aee4294 <pthread_mutex_unlock+316>:  ldw -54(,sp),rp
    0x7aee4298 <pthread_mutex_unlock+320>:  ldw -3c(,sp),r4
    0x7aee429c <pthread_mutex_unlock+324>:  bv r0(rp)
    0x7aee42a0 <pthread_mutex_unlock+328>:  ldw,mb -40(,sp),r3

Which looks like an epilogue. The next region is:

    unwind_table_entry (0x401db148):
            region_start = 0x7aee42a4 <pthread_mutex_unlock+332>
            region_end = 0x7aee42e4 <pthread_mutex_unlock+396>
            flags = Args_stored Save_RP
            Region_description = 0x0
            Entry_FR = 0x0
            Entry_GR = 0x3
            Total_frame_size = 0x10

And the code at the start of the region is:

    0x7aee42a4 <pthread_mutex_unlock+332>:  stw rp,-14(,sp)
    0x7aee42a8 <pthread_mutex_unlock+336>:  stw,ma r3,80(,sp)
    0x7aee42ac <pthread_mutex_unlock+340>:  stw r4,-7c(,sp)
    0x7aee42b0 <pthread_mutex_unlock+344>:  stw r5,-78(,sp)
    0x7aee42b4 <pthread_mutex_unlock+348>:  ldi 36,r3

Which again looks like a sensible prologue to me.

But I am a bit dumbfounded with the last region.  By the way, 
pthread_mutex_unlock+960 is almost the end of a region:

    (gdb) maintenance print unwind &pthread_mutex_unlock+960
    unwind_table_entry (0x401db170):
            region_start = 0x7aee4454 <pthread_mutex_unlock+764>
            region_end = 0x7aee451c <pthread_mutex_unlock+964>
            flags = Args_stored Save_RP
            Region_description = 0x0
            Entry_FR = 0x0
            Entry_GR = 0x1
            Total_frame_size = 0x10

And the instructions the code is jumping to are:

    0x7aee4518 <pthread_mutex_unlock+960>:  bv r0(rp)
    0x7aee451c <pthread_mutex_unlock+964>:  ldw,mb -80(,sp),r3

It's the last instructions of something that looks like a function
epilogue to me:

    0x7aee450c <pthread_mutex_unlock+948>:  ldw -20(,sp),r19
    0x7aee4510 <pthread_mutex_unlock+952>:  ldw -94(,sp),rp
    0x7aee4514 <pthread_mutex_unlock+956>:  ldi 0,ret0
    0x7aee4518 <pthread_mutex_unlock+960>:  bv r0(rp)
    0x7aee451c <pthread_mutex_unlock+964>:  ldw,mb -80(,sp),r3

Would you have an idea or how to find the return address?


procedure Task_Switch is

   -- Declaractions --

   task type Callee is
      entry Finito;
   end Callee;
   type Callee_Ptr is access Callee;

   task type Caller is
   end Caller;
   type Caller_Ptr is access Caller;

   procedure Break_Me;

   My_Caller : Caller_Ptr;
   My_Callee : Callee_Ptr;

   -- Bodies --

   task body Callee is
      --  Just wait until we are told to terminate this task.
      --  This is just to maintain this task alive.
      accept Finito do
      end Finito;
   end Callee;

   task body Caller is
   end Caller;

   procedure Break_Me is
      null;  -- line 43
   end Break_Me;


   --  Make sure to create the Callee task first... And then give it
   --  enough time to complete its activation phase before we start
   --  the Caller task.
   My_Callee := new Callee;
   delay 0.1;

   My_Caller := new Caller;

end Task_Switch;

More information about the Gdb-patches mailing list