43873a6
2004-06-22  Andrew Cagney  <cagney@gnu.org>
43873a6
43873a6
	* rs6000-tdep.c (struct rs6000_framedata): Add field "func_start".
43873a6
	(skip_prologue): Delete local variable "orig_pc", use
43873a6
	"func_start".  Add local variable "num_skip_linux_syscall_insn",
43873a6
	use to skip over first half of a GNU/Linux syscall and update
43873a6
	"func_start".
43873a6
43873a6
Index: ./gdb/rs6000-tdep.c
43873a6
===================================================================
43873a6
RCS file: /cvs/src/src/gdb/rs6000-tdep.c,v
43873a6
retrieving revision 1.215
43873a6
diff -p -u -r1.215 rs6000-tdep.c
43873a6
--- ./gdb/rs6000-tdep.c	20 Jun 2004 17:18:06 -0000	1.215
43873a6
+++ ./gdb/rs6000-tdep.c	22 Jun 2004 19:06:46 -0000
43873a6
@@ -71,6 +71,7 @@
43873a6
 
43873a6
 struct rs6000_framedata
43873a6
   {
43873a6
+    CORE_ADDR func_start;	/* True function start.  */
43873a6
     int offset;			/* total size of frame --- the distance
43873a6
 				   by which we decrement sp to allocate
43873a6
 				   the frame */
43873a6
@@ -694,7 +695,6 @@ store_param_on_stack_p (unsigned long op
43873a6
 static CORE_ADDR
43873a6
 skip_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct rs6000_framedata *fdata)
43873a6
 {
43873a6
-  CORE_ADDR orig_pc = pc;
43873a6
   CORE_ADDR last_prologue_pc = pc;
43873a6
   CORE_ADDR li_found_pc = 0;
43873a6
   char buf[4];
43873a6
@@ -712,6 +712,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
43873a6
   int minimal_toc_loaded = 0;
43873a6
   int prev_insn_was_prologue_insn = 1;
43873a6
   int num_skip_non_prologue_insns = 0;
43873a6
+  int num_skip_ppc64_gnu_linux_syscall_insn = 0;
43873a6
   int r0_contains_arg = 0;
43873a6
   const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (current_gdbarch);
43873a6
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
43873a6
@@ -732,6 +733,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
43873a6
     lim_pc = refine_prologue_limit (pc, lim_pc);
43873a6
 
43873a6
   memset (fdata, 0, sizeof (struct rs6000_framedata));
43873a6
+  fdata->func_start = pc;
43873a6
   fdata->saved_gpr = -1;
43873a6
   fdata->saved_fpr = -1;
43873a6
   fdata->saved_vr = -1;
43873a6
@@ -760,6 +762,55 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
43873a6
 	break;
43873a6
       op = extract_signed_integer (buf, 4);
43873a6
 
43873a6
+      /* A PPC64 GNU/Linux system call function is split into two
43873a6
+	 sub-functions: a non-threaded fast-path (__NAME_nocancel)
43873a6
+	 which does not use a frame; and a threaded slow-path
43873a6
+	 (Lpseudo_cancel) that does create a frame.  Ref:
43873a6
+	 nptl/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
43873a6
+
43873a6
+	 *INDENT-OFF*
43873a6
+	 NAME:
43873a6
+	 	SINGLE_THREAD_P
43873a6
+	 	bne- .Lpseudo_cancel
43873a6
+	 __NAME_nocancel:
43873a6
+	 	li r0,162
43873a6
+	 	sc
43873a6
+	 	bnslr+
43873a6
+	 	b 0x7fe014ef64 <.__syscall_error>
43873a6
+	 Lpseudo_cancel:
43873a6
+	 	stdu r1,-128(r1)
43873a6
+	 	...
43873a6
+	 *INDENT-ON*
43873a6
+
43873a6
+	 Unfortunatly, because the latter case uses a local label (not
43873a6
+	 in the symbol table) a PC in "Lpseudo_cancel" appears to be
43873a6
+	 in "__NAME_nocancel".  The following code recognizes this,
43873a6
+	 adjusting FUNC_START to point to where "Lpseudo_cancel"
43873a6
+	 should be, and parsing the prologue sequence as if
43873a6
+	 "Lpseudo_cancel" was the entry point.  */
43873a6
+
43873a6
+      if (((op & 0xffff0000) == 0x38000000 /* li r0,N */
43873a6
+	   && pc == fdata->func_start + 0
43873a6
+	   && num_skip_ppc64_gnu_linux_syscall_insn == 0)
43873a6
+	  || (op == 0x44000002 /* sc */
43873a6
+	      && pc == fdata->func_start + 4
43873a6
+	      && num_skip_ppc64_gnu_linux_syscall_insn == 1)
43873a6
+	  || (op == 0x4ca30020 /* bnslr+ */
43873a6
+	      && pc == fdata->func_start + 8
43873a6
+	      && num_skip_ppc64_gnu_linux_syscall_insn == 2))
43873a6
+	{
43873a6
+	  num_skip_ppc64_gnu_linux_syscall_insn++;
43873a6
+	  continue;
43873a6
+	}
43873a6
+      else if ((op & 0xfc000003) == 0x48000000 /* b __syscall_error */
43873a6
+	       && pc == fdata->func_start + 12
43873a6
+	       && num_skip_ppc64_gnu_linux_syscall_insn == 3)
43873a6
+	{
43873a6
+	  num_skip_ppc64_gnu_linux_syscall_insn = -1;
43873a6
+	  fdata->func_start = pc;
43873a6
+	  continue;
43873a6
+	}
43873a6
+
43873a6
       if ((op & 0xfc1fffff) == 0x7c0802a6)
43873a6
 	{			/* mflr Rx */
43873a6
 	  /* Since shared library / PIC code, which needs to get its
43873a6
@@ -913,7 +964,7 @@ skip_prologue (CORE_ADDR pc, CORE_ADDR l
43873a6
 	  fdata->frameless = 0;
43873a6
 	  /* Don't skip over the subroutine call if it is not within
43873a6
 	     the first three instructions of the prologue.  */
43873a6
-	  if ((pc - orig_pc) > 8)
43873a6
+	  if ((pc - fdata->func_start) > 8)
43873a6
 	    break;
43873a6
 
43873a6
 	  op = read_memory_integer (pc + 4, 4);