Index: gdb/sparc64-linux-tdep.c |
diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c |
index 019af2b8a59c2c44db6fb5c52a566eea57dc5c80..f6ddff0f34be2342d89d59b4bca24380552dfa91 100644 |
--- a/gdb/sparc64-linux-tdep.c |
+++ b/gdb/sparc64-linux-tdep.c |
@@ -1,6 +1,6 @@ |
/* Target-dependent code for GNU/Linux UltraSPARC. |
- Copyright (C) 2003-2005, 2007-2012 Free Software Foundation, Inc. |
+ Copyright (C) 2003-2013 Free Software Foundation, Inc. |
This file is part of GDB. |
@@ -174,7 +174,7 @@ sparc64_linux_supply_core_fpregset (const struct regset *regset, |
struct regcache *regcache, |
int regnum, const void *fpregs, size_t len) |
{ |
- sparc64_supply_fpregset (regcache, regnum, fpregs); |
+ sparc64_supply_fpregset (&sparc64_bsd_fpregset, regcache, regnum, fpregs); |
} |
static void |
@@ -182,7 +182,7 @@ sparc64_linux_collect_core_fpregset (const struct regset *regset, |
const struct regcache *regcache, |
int regnum, void *fpregs, size_t len) |
{ |
- sparc64_collect_fpregset (regcache, regnum, fpregs); |
+ sparc64_collect_fpregset (&sparc64_bsd_fpregset, regcache, regnum, fpregs); |
} |
/* Set the program counter for process PTID to PC. */ |
@@ -233,6 +233,50 @@ sparc64_linux_get_syscall_number (struct gdbarch *gdbarch, |
} |
+/* 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 @@ 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'. */ |