sparc: support single-stepping over longjmp calls.

2013-11-18  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 commit is contained in:
Jose E. Marchesi 2013-11-18 04:37:05 -08:00
parent 4b4589ada7
commit d0b5971ae7
4 changed files with 89 additions and 0 deletions

View File

@ -1,3 +1,12 @@
2013-11-18 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.
2013-11-18 Pedro Alves <palves@redhat.com>
* dwarf2-frame.c (read_addr_from_reg): Remove stale comment and

View File

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

View File

@ -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. */

View File

@ -232,6 +232,50 @@ sparc64_linux_get_syscall_number (struct gdbarch *gdbarch,
return ret;
}
/* 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
@ -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'. */