[RFC/RFA/hppa] unwind pc in bottom frame using correct register

Joel Brobecker brobecker@adacore.com
Sat Dec 4 05:31:00 GMT 2004


This is where I truly show how ignorant I am about the hppa
archictecture... I need to stop working on GDB for now, as I need
to prepare my trip to Paris on sunday morning (will be working from
there for the week).

This is an interesting bug that I hit... I used the little Ada program
copied at the end of this email. If you have a GNAT compiler, you can
build it using the following command:

        % gnatmake -g task_switch

I tried switching to a specific thread, and I'm having some trouble.
The interesting part is that the thread switch would fail the first
time I attempt it (this is with gdb-6.3 but the same goes with head):

        (gdb) b break_me
        Breakpoint 1 at 0xa684: file task_switch.adb, line 43.
        (gdb) run
        Starting program: /[...]/task_switch 
        [New thread 2 (system thread 18450)]
        [New thread 3 (system thread 18451)]
        [Switching to thread 3 (system thread 18451)]
        
        Breakpoint 1, task_switch.break_me () at task_switch.adb:43
        43         end Break_Me;
        (gdb) thread 2
        [Switching to thread 2 (system thread 18450)]#0  0x7b040820 in ?? ()
        (gdb) bt
        #0  0x7b040820 in ?? ()
        warning: Cannot find bounds of current function (@0x0),
        unwinding will fail.

The "0x7b040820" address is wrong. And this also cause the "bt"
failure.

If I quit GDB, and then retry, this time it "works". Try it several
times after, it will alway "work". Rebuild the program, and it will
stop working ONE time. Then it'll "work".

        (gdb) thread 2
        [Switching to thread 2 (system thread 18666)]#0  0x00013220 in system.tasking.rendezvous.accept_trivial ()
        (gdb) bt
        #0  0x00013220 in system.tasking.rendezvous.accept_trivial ()
        #1  0x7aedf448 in _lwp_cond_timedwait () from /usr/lib/libpthread.1
        #2  0x7aedf184 in pthread_cond_wait () from /usr/lib/libpthread.1
        #3  0x7aedf120 in pthread_cond_wait () from /usr/lib/libpthread.1
        #4  0x000164b0 in system.tasking.rendezvous.wait_for_call ()
        #5  0x0001345c in system.tasking.rendezvous.accept_trivial ()
        #6  0x0000a4b8 in task_switch.callee (<_task>=0x4001d020)
            at task_switch.adb:29
        #7  0x0000a458 in task_switch__calleeB___3 () at task_switch.adb:24
        #8  0x0001780c in system.tasking.stages.task_wrapper ()
        #9  0x000176e0 in system__tasking__stages__task_wrapper ()
        #10 0x7aee0f60 in __pthread_create_system () from /usr/lib/libpthread.1
        #11 0x7aee0f08 in __pthread_create_system () from /usr/lib/libpthread.1

But if you look a bit closer, you see that the callstack is not
that good yet. Indeed, frame #0 is not correct. The rest of the frame
looks OK, but only by chance most probably.

That's when I found that hppa_unwind_pc() always returns the value of
the PCOQ register. On the other hand, the register used by
hppa_target_read_pc() to get PC depends on the value of the flags
register (we get the PC either from PCOQ, or GR31). I have quickly
scanned some of the docs I found on hppa, and couldn't find what this
refers to. So I am a bit in the dark.  I have asked one of my coworkers
in Paris to illuminate me, so I expect to be more knowledgeable on
monday :-).

In any case, this seemed inconsistent, so I came up with the idea
of calling hppa_target_read_pc() when uwinding the PC from the
sentinel frame. And that fixes the problem nicely:

        (gdb) bt
        #0  0x7afff708 in __ksleep () from /usr/lib/libc.2
        #1  0x7aedf448 in _lwp_cond_timedwait () from /usr/lib/libpthread.1
        #2  0x7aedf184 in pthread_cond_wait () from /usr/lib/libpthread.1
        #3  0x7aedf120 in pthread_cond_wait () from /usr/lib/libpthread.1
        #4  0x000164b0 in system.tasking.rendezvous.wait_for_call ()
        #5  0x0001345c in system.tasking.rendezvous.accept_trivial ()
        #6  0x0000a4b8 in task_switch.callee (<_task>=0x4001d020)
            at task_switch.adb:29
        #7  0x0000a458 in task_switch__calleeB___3 () at task_switch.adb:24
        #8  0x0001780c in system.tasking.stages.task_wrapper ()
        #9  0x000176e0 in system__tasking__stages__task_wrapper ()
        #10 0x7aee0f60 in __pthread_create_system () from /usr/lib/libpthread.1
        #11 0x7aee0f08 in __pthread_create_system () from /usr/lib/libpthread.1

This is much more plausible, and is actually what we get with
gdb-5.3 (minus the linker stubs).

I only spotted one problem in the testsuite: We get an error when trying
to get the flags register off a core file. We get 2 new fails in
corefile.exp. So I added an additional check against being in a core
file, and voila, no regression.

It's all a bit experimental, because of my lack of knowledge of the hppa
architecture. But I feel I might be on the right track, so I'm posting
the patch here, before leaving.

2004-12-03  Joel Brobecker  <brobecker@gnat.com>

        * hppa-tdep.c (hppa_unwind_pc): Use hppa_target_read_pc to fetch
        the PC for the sentinel frame, except when debugging a core file.

Tested on hppa2.0w-hp-hpux11.00. How does it look?

BTW: It would be nice to also comment on the fact that we don't
     call hppa_target_read_pc() if !target_has_execution and explain
     why. But I don't know why we don't have access to the flags reg
     yet. So I'll add that as a followup patch as soon as I have figured
     it out.

-- 
Joel

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
   begin
      --  Just wait until we are told to terminate this task.
      --  This is just to maintain this task alive.
      accept Finito do
         null;
      end Finito;
   end Callee;

   task body Caller is
   begin
      Break_Me;
      My_Callee.Finito;
   end Caller;

   procedure Break_Me is
   begin
      null;
   end Break_Me;

begin

   --  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;

-------------- next part --------------
Index: hppa-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.c,v
retrieving revision 1.183
diff -u -p -r1.183 hppa-tdep.c
--- hppa-tdep.c	1 Dec 2004 06:54:56 -0000	1.183
+++ hppa-tdep.c	4 Dec 2004 04:15:30 -0000
@@ -2185,6 +2185,12 @@ hppa_unwind_dummy_id (struct gdbarch *gd
 static CORE_ADDR
 hppa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
+  /* If unwinding the PC from the sentinel frame, then which register
+     to read depends on the value of the status register.  Use
+     hppa_target_read_pc(), it knows where to get the PC.  */
+  if (target_has_execution && frame_relative_level (next_frame) < 0)
+    return hppa_target_read_pc (inferior_ptid);
+
   return frame_unwind_register_signed (next_frame, HPPA_PCOQ_HEAD_REGNUM) & ~3;
 }
 


More information about the Gdb-patches mailing list