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] |
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); + + +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 8 Oct 2013 17:13:35 -0000 @@ -233,6 +233,54 @@ } +/* 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; +} + + 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'. */
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |