* [PATCH] [SPARC64] Figure out where a longjmp will land
@ 2013-10-08 17:25 Jose E. Marchesi
2013-10-08 20:23 ` Tom Tromey
0 siblings, 1 reply; 12+ messages in thread
From: Jose E. Marchesi @ 2013-10-08 17:25 UTC (permalink / raw)
To: gdb-patches
This is related to PR gdb/14971. All tests in gdb.base/longjmp.exp pass
after applying this patch.
Note that in sparc64 glibc does not install probes in setjmp, nor it
mangles pointers.
Tested on sparc64-*-linux-gnu.
2013-10-08 Jose E. Marchesi <jose.marchesi@oracle.com>
PR gdb/14971
* 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 8 Oct 2013 17:13:35 -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 8 Oct 2013 17:13:35 -0000
@@ -202,6 +202,12 @@
extern void sparc_collect_rwindow (const struct regcache *regcache,
CORE_ADDR sp, int regnum);
+\f
+
+extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
+
+\f
+
/* 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 8 Oct 2013 17:13:35 -0000
@@ -233,6 +233,54 @@
}
\f
+/* 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)
+{
+ 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;
+}
+
+\f
static void
sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -272,6 +320,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'. */
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-08 17:25 [PATCH] [SPARC64] Figure out where a longjmp will land Jose E. Marchesi
@ 2013-10-08 20:23 ` Tom Tromey
2013-10-08 20:49 ` Sergio Durigan Junior
2013-10-08 21:51 ` Jose E. Marchesi
0 siblings, 2 replies; 12+ messages in thread
From: Tom Tromey @ 2013-10-08 20:23 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: gdb-patches
>>>>> "Jose" == Jose E Marchesi <jose.marchesi@oracle.com> writes:
Jose> Note that in sparc64 glibc does not install probes in setjmp, nor it
Jose> mangles pointers.
In this case adding the probes is marginal; but you will probably want
to write the probe support for sparc64 in gdb anyway, because there are
other probes available that provide more noticeable benefits...
Jose> + return X_A(insn);
Space before the "(".
Someone else will have to do the real review though.
Tom
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-08 20:23 ` Tom Tromey
@ 2013-10-08 20:49 ` Sergio Durigan Junior
2013-10-08 21:51 ` Jose E. Marchesi
1 sibling, 0 replies; 12+ messages in thread
From: Sergio Durigan Junior @ 2013-10-08 20:49 UTC (permalink / raw)
To: Tom Tromey; +Cc: Jose E. Marchesi, gdb-patches
On Tuesday, October 08 2013, Tom Tromey wrote:
>>>>>> "Jose" == Jose E Marchesi <jose.marchesi@oracle.com> writes:
>
> Jose> Note that in sparc64 glibc does not install probes in setjmp, nor it
> Jose> mangles pointers.
>
> In this case adding the probes is marginal; but you will probably want
> to write the probe support for sparc64 in gdb anyway, because there are
> other probes available that provide more noticeable benefits...
Let me know if you need some help with that. It shouldn't be hard to
implement it, though.
--
Sergio
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-08 20:23 ` Tom Tromey
2013-10-08 20:49 ` Sergio Durigan Junior
@ 2013-10-08 21:51 ` Jose E. Marchesi
2013-10-17 5:57 ` Joel Brobecker
1 sibling, 1 reply; 12+ messages in thread
From: Jose E. Marchesi @ 2013-10-08 21:51 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
Jose> Note that in sparc64 glibc does not install probes in setjmp, nor it
Jose> mangles pointers.
In this case adding the probes is marginal; but you will probably want
to write the probe support for sparc64 in gdb anyway, because there are
other probes available that provide more noticeable benefits...
Yes, I will take a look at the several places where probes are used in
other architetures.
Jose> + return X_A(insn);
Space before the "(".
Updated patch follows.
Many thanks for reviewing :)
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 8 Oct 2013 17:13:35 -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 8 Oct 2013 17:13:35 -0000
@@ -202,6 +202,12 @@
extern void sparc_collect_rwindow (const struct regcache *regcache,
CORE_ADDR sp, int regnum);
+\f
+
+extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
+
+\f
+
/* 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 8 Oct 2013 17:13:35 -0000
@@ -233,6 +233,54 @@
}
\f
+/* 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)
+{
+ 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;
+}
+
+\f
static void
sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -272,6 +320,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'. */
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-08 21:51 ` Jose E. Marchesi
@ 2013-10-17 5:57 ` Joel Brobecker
2013-10-17 11:31 ` Jose E. Marchesi
2013-10-20 19:27 ` Mark Kettenis
0 siblings, 2 replies; 12+ messages in thread
From: Joel Brobecker @ 2013-10-17 5:57 UTC (permalink / raw)
To: Jose E. Marchesi; +Cc: Tom Tromey, gdb-patches
> 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).
I assume that this was validated against our testsuite, and that
no new regressions were detected?
Thank you.
> +/* 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. */
This prevents maintenance issues if we start modifying the "method"'s
specifications. If there is anything from the documentation that
you think is worth preserving locally, please do.
Now, I see that "method" is actually not documented, yet. I will try
fixing that as best as I can.
--
Joel
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-17 5:57 ` Joel Brobecker
@ 2013-10-17 11:31 ` Jose E. Marchesi
2013-10-20 19:32 ` Mark Kettenis
2013-10-20 19:27 ` Mark Kettenis
1 sibling, 1 reply; 12+ messages in thread
From: Jose E. Marchesi @ 2013-10-17 11:31 UTC (permalink / raw)
To: Joel Brobecker; +Cc: Tom Tromey, gdb-patches
> 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);
+\f
+
+extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
+
+\f
+
/* 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 @@
}
\f
+/* 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;
+}
+
+\f
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'. */
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-17 11:31 ` Jose E. Marchesi
@ 2013-10-20 19:32 ` Mark Kettenis
2013-10-21 12:52 ` Jose E. Marchesi
0 siblings, 1 reply; 12+ messages in thread
From: Mark Kettenis @ 2013-10-20 19:32 UTC (permalink / raw)
To: jose.marchesi; +Cc: brobecker, tromey, gdb-patches
> From: jose.marchesi@oracle.com (Jose E. Marchesi)
> Date: Thu, 17 Oct 2013 13:33:43 +0200
>
> > 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.
Diff looks good to me, although I'm not really familliar with the
glibc longjmp implementation. See my note about pinging Dave Miller.
One nit though...
> 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);
>
> +\f
> +
> +extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
> +
> +\f
> +
Seems a bit excessive to put these additional ^L's in there.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-20 19:32 ` Mark Kettenis
@ 2013-10-21 12:52 ` Jose E. Marchesi
0 siblings, 0 replies; 12+ messages in thread
From: Jose E. Marchesi @ 2013-10-21 12:52 UTC (permalink / raw)
To: Mark Kettenis; +Cc: brobecker, tromey, gdb-patches
> 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);
>
> +\f
> +
> +extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
> +
> +\f
> +
Seems a bit excessive to put these additional ^L's in there.
Amended in 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 21 Oct 2013 12:48:04 -0000
@@ -220,6 +220,8 @@
const struct regcache *regcache,
int regnum, void *fpregs);
+extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
+
/* Functions and variables exported from sparc-sol2-tdep.c. */
/* Register offsets for Solaris 2. */
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 @@
}
\f
+/* 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;
+}
+
+\f
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'. */
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-17 5:57 ` Joel Brobecker
2013-10-17 11:31 ` Jose E. Marchesi
@ 2013-10-20 19:27 ` Mark Kettenis
2013-10-21 12:53 ` Jose E. Marchesi
1 sibling, 1 reply; 12+ messages in thread
From: Mark Kettenis @ 2013-10-20 19:27 UTC (permalink / raw)
To: brobecker; +Cc: jose.marchesi, tromey, gdb-patches
> Date: Thu, 17 Oct 2013 09:57:36 +0400
> From: Joel Brobecker <brobecker@adacore.com>
>
> > 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).
Well, for the Linux-specific bits it is a good idea to make sure that
David S. Miller sees the changes as well.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-20 19:27 ` Mark Kettenis
@ 2013-10-21 12:53 ` Jose E. Marchesi
2013-10-22 8:22 ` Mark Kettenis
0 siblings, 1 reply; 12+ messages in thread
From: Jose E. Marchesi @ 2013-10-21 12:53 UTC (permalink / raw)
To: Mark Kettenis; +Cc: brobecker, tromey, gdb-patches
> 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).
Well, for the Linux-specific bits it is a good idea to make sure that
David S. Miller sees the changes as well.
Is he subscribed to gdb-patches? Shall I address him directly?
^ permalink raw reply [flat|nested] 12+ messages in thread* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-21 12:53 ` Jose E. Marchesi
@ 2013-10-22 8:22 ` Mark Kettenis
2013-11-18 14:02 ` Jose E. Marchesi
0 siblings, 1 reply; 12+ messages in thread
From: Mark Kettenis @ 2013-10-22 8:22 UTC (permalink / raw)
To: jose.marchesi; +Cc: brobecker, tromey, gdb-patches
> From: jose.marchesi@oracle.com (Jose E. Marchesi)
> Date: Mon, 21 Oct 2013 14:55:45 +0200
>
> > 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).
>
> Well, for the Linux-specific bits it is a good idea to make sure that
> David S. Miller sees the changes as well.
>
> Is he subscribed to gdb-patches?
Probably not.
> Shall I address him directly?
So yes, that might be a good idea.
Your last diff is fine with me, so if Dave doesn't respond within a
couple of days after you ping him, feel free to move ahead with this.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] [SPARC64] Figure out where a longjmp will land
2013-10-22 8:22 ` Mark Kettenis
@ 2013-11-18 14:02 ` Jose E. Marchesi
0 siblings, 0 replies; 12+ messages in thread
From: Jose E. Marchesi @ 2013-11-18 14:02 UTC (permalink / raw)
To: Mark Kettenis; +Cc: brobecker, tromey, gdb-patches
> Shall I address him directly?
So yes, that might be a good idea.
Your last diff is fine with me, so if Dave doesn't respond within a
couple of days after you ping him, feel free to move ahead with this.
I just committed the attached amended patch, reviewed by Mark and Dave
off-list and authorized by Mark.
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.
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
index 880d276..4057d0d 100644
--- a/gdb/sparc-tdep.c
+++ b/gdb/sparc-tdep.c
@@ -121,6 +121,37 @@ sparc_is_unimp_insn (CORE_ADDR pc)
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)
+{
+ /* The branch instructions featuring an annul bit can be identified
+ by the following bit patterns:
+
+ OP=0
+ OP2=1: Branch on Integer Condition Codes with Prediction (BPcc).
+ OP2=2: Branch on Integer Condition Codes (Bcc).
+ OP2=5: Branch on FP Condition Codes with Prediction (FBfcc).
+ OP2=6: Branch on FP Condition Codes (FBcc).
+ OP2=3 && Bit28=0:
+ Branch on Integer Register with Prediction (BPr).
+
+ This leaves out ILLTRAP (OP2=0), SETHI/NOP (OP2=4) and the V8
+ coprocessor branch instructions (Op2=7). */
+
+ const unsigned long insn = sparc_fetch_instruction (pc);
+ const unsigned op2 = X_OP2 (insn);
+
+ if ((X_OP (insn) == 0)
+ && ((op2 == 1) || (op2 == 2) || (op2 == 5) || (op2 == 6)
+ || ((op2 == 3) && ((insn & 0x10000000) == 0))))
+ return X_A (insn);
+ else
+ return 0;
+}
+
/* OpenBSD/sparc includes StackGhost, which according to the author's
website http://stackghost.cerias.purdue.edu "... transparently and
automatically protects applications' stack frames; more
diff --git a/gdb/sparc-tdep.h b/gdb/sparc-tdep.h
index cafc627..6fd7641 100644
--- a/gdb/sparc-tdep.h
+++ b/gdb/sparc-tdep.h
@@ -220,6 +220,8 @@ extern void sparc32_collect_fpregset (const struct sparc_fpregset *fpregset,
const struct regcache *regcache,
int regnum, void *fpregs);
+extern int sparc_is_annulled_branch_insn (CORE_ADDR pc);
+
/* Functions and variables exported from sparc-sol2-tdep.c. */
/* Register offsets for Solaris 2. */
diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c
index 3f53f6c..f6ddff0 100644
--- a/gdb/sparc64-linux-tdep.c
+++ b/gdb/sparc64-linux-tdep.c
@@ -233,6 +233,50 @@ sparc64_linux_get_syscall_number (struct gdbarch *gdbarch,
}
\f
+/* 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;
+}
+
+\f
static void
sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
@@ -272,6 +316,9 @@ sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
/* 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'. */
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2013-11-18 12:51 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-08 17:25 [PATCH] [SPARC64] Figure out where a longjmp will land Jose E. Marchesi
2013-10-08 20:23 ` Tom Tromey
2013-10-08 20:49 ` Sergio Durigan Junior
2013-10-08 21:51 ` Jose E. Marchesi
2013-10-17 5:57 ` Joel Brobecker
2013-10-17 11:31 ` Jose E. Marchesi
2013-10-20 19:32 ` Mark Kettenis
2013-10-21 12:52 ` Jose E. Marchesi
2013-10-20 19:27 ` Mark Kettenis
2013-10-21 12:53 ` Jose E. Marchesi
2013-10-22 8:22 ` Mark Kettenis
2013-11-18 14:02 ` Jose E. Marchesi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox