This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] [SPARC64] Figure out where a longjmp will land


    > 2013-10-08  Jose E. Marchesi  <jose.marchesi@oracle.com>
    > 
    > 	* sparc-tdep.c (sparc_is_annulled_branch_insn): New function.
    > 	* sparc-tdep.h: And its prototype.
    > 
    > 	* sparc64-linux-tdep.c (sparc64_linux_get_longjmp_target): New
    > 	function.
    > 	(sparc64_linux_init_abi): Register the get_longjmp_target hook.
    
    This looks reasonable to me, with a minor correction requested below.
    But Sparc patches normally get reviewed by MarkK, so can you give it
    another week before checking the final version in? (remember that
    when you check something in that is different from the patch already
    posted, an updated patch should be sent to the list, for the
    record).

Noted, but I don't have write access to the CVS so I can't check
anything in.
    
    I assume that this was validated against our testsuite, and that
    no new regressions were detected?

Yes.  I always run the testsuite for regressions before submitting any
patch.  I tested this on sparc64-unknown-linux-gnu.
    
    > +/* Figure out where a longjmp will land.  Get the args out of the
    > +   output registers.  We expect the first arg to be a pointer to the
    > +   jmp_buf structure from which we extract the address that we will
    > +   land at.  This address is copied into PC.  This routine returns
    > +   non-zero on success.  */
    > +
    > +static int
    > +sparc64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
    
    This function is expected to implement a gdbarch callback, so you do
    not need to repeat the spec, which is expected to already be documented
    in gdbarch.h. Instead, use:
    
        /* Implement the "get_longjmp_target" gdbarch method.  */

Amended patch below.

2013-10-08  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* sparc-tdep.c (sparc_is_annulled_branch_insn): New function.
	* sparc-tdep.h: And its prototype.

	* sparc64-linux-tdep.c (sparc64_linux_get_longjmp_target): New
	function.
	(sparc64_linux_init_abi): Register the get_longjmp_target hook.


Index: sparc-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc-tdep.c,v
retrieving revision 1.233
diff -u -r1.233 sparc-tdep.c
--- sparc-tdep.c	24 Jun 2013 22:18:32 -0000	1.233
+++ sparc-tdep.c	17 Oct 2013 11:27:05 -0000
@@ -121,6 +121,17 @@
   return ((insn & 0xc1c00000) == 0);
 }
 
+/* Return non-zero if the instruction corresponding to PC is an
+   "annulled" branch, i.e. the annul bit is set.  */
+
+int
+sparc_is_annulled_branch_insn (CORE_ADDR pc)
+{
+  const unsigned long insn = sparc_fetch_instruction (pc);
+
+  return X_A (insn);
+}
+
 /* OpenBSD/sparc includes StackGhost, which according to the author's
    website http://stackghost.cerias.purdue.edu "... transparently and
    automatically protects applications' stack frames; more
Index: sparc-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/sparc-tdep.h,v
retrieving revision 1.33
diff -u -r1.33 sparc-tdep.h
--- sparc-tdep.h	1 Jan 2013 06:32:51 -0000	1.33
+++ sparc-tdep.h	17 Oct 2013 11:27:05 -0000
@@ -202,6 +202,12 @@
 extern void sparc_collect_rwindow (const struct regcache *regcache,
 				   CORE_ADDR sp, int regnum);
 
+
+
+extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
+
+
+
 /* Register offsets for SunOS 4.  */
 extern const struct sparc_gregset sparc32_sunos4_gregset;
 extern const struct sparc_fpregset sparc32_sunos4_fpregset;
Index: sparc64-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/sparc64-linux-tdep.c,v
retrieving revision 1.31
diff -u -r1.31 sparc64-linux-tdep.c
--- sparc64-linux-tdep.c	1 Jan 2013 06:32:51 -0000	1.31
+++ sparc64-linux-tdep.c	17 Oct 2013 11:27:05 -0000
@@ -233,6 +233,50 @@
 }
 
 
+/* Implement the "get_longjmp_target" gdbarch method.  */
+
+static int
+sparc64_linux_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  CORE_ADDR jb_addr;
+  gdb_byte buf[8];
+
+  jb_addr = get_frame_register_unsigned (frame, SPARC_O0_REGNUM);
+
+  /* setjmp and longjmp in SPARC64 are implemented in glibc using the
+     setcontext and getcontext system calls respectively.  These
+     system calls operate on ucontext_t structures, which happen to
+     partially have the same structure than jmp_buf.  However the
+     ucontext returned by getcontext, and thus the jmp_buf structure
+     returned by setjmp, contains the context of the trap instruction
+     in the glibc __[sig]setjmp wrapper, not the context of the user
+     code calling setjmp.
+
+     %o7 in the jmp_buf structure is stored at offset 18*8 in the
+     mc_gregs array, which is itself located at offset 32 into
+     jmp_buf.  See bits/setjmp.h.  This register contains the address
+     of the 'call setjmp' instruction in user code.
+
+     In order to determine the longjmp target address in the
+     initiating frame we need to examine the call instruction itself,
+     in particular whether the annul bit is set.  If it is not set
+     then we need to jump over the instruction at the delay slot.  */
+
+  if (target_read_memory (jb_addr + 32 + (18 * 8), buf, 8))
+    return 0;
+
+  *pc = extract_unsigned_integer (buf, 8, gdbarch_byte_order (gdbarch));
+
+  if (!sparc_is_annulled_branch_insn (*pc))
+      *pc += 4; /* delay slot insn  */
+  *pc += 4; /* call insn  */
+
+  return 1;
+}
+
+
 
 static void
 sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -272,6 +316,9 @@
   /* Make sure we can single-step over signal return system calls.  */
   tdep->step_trap = sparc64_linux_step_trap;
 
+  /* Make sure we can single-step over longjmp calls.  */
+  set_gdbarch_get_longjmp_target (gdbarch, sparc64_linux_get_longjmp_target);
+
   set_gdbarch_write_pc (gdbarch, sparc64_linux_write_pc);
 
   /* Functions for 'catch syscall'.  */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]