From 78a0fd579cff3adaf9a83169053f65e2749074ca Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 21 Apr 2005 19:38:20 +0000 Subject: [PATCH] * sparc-linux-tdep.c (sparc32_linux_sigtramp_p): Fix signal return stub symbol names, __restore and __restore_rt are the i386 symbol names not the sparc ones. (sparc32_linux_sigtramp_frame_cache): Document bits/sigcontext.h as where the offsets were obtained from. * sparc64-linux-tdep.c (LINUX64_RT_SIGTRAMP_INSN0, LINUX64_RT_SIGTRAMP_INSN1): New defines. (sparc64_linux_sigtramp_start, sparc64_linux_sigtramp_p, sparc64_linux_sigtramp_frame_cache, sparc64_linux_sigtramp_frame_this_id, sparc64_linux_sigtramp_frame_prev_register, sparc64_linux_sigtramp_frame_sniffer): New functions. (sparc64_linux_sigtramp_frame_unwind): New frame unwinder. (sparc64_linux_init_abi): Register sigtramp frame sniffer. * Makefile.in (sparc64-linux-tdep.o): Update dependencies. --- gdb/ChangeLog | 18 ++++ gdb/Makefile.in | 6 +- gdb/sparc-linux-tdep.c | 15 ++-- gdb/sparc64-linux-tdep.c | 177 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+), 8 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index af6d7e55a07..c1bb561db9d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2005-04-20 David S. Miller + + * sparc-linux-tdep.c (sparc32_linux_sigtramp_p): Fix + signal return stub symbol names, __restore and __restore_rt are + the i386 symbol names not the sparc ones. + (sparc32_linux_sigtramp_frame_cache): Document bits/sigcontext.h + as where the offsets were obtained from. + * sparc64-linux-tdep.c (LINUX64_RT_SIGTRAMP_INSN0, + LINUX64_RT_SIGTRAMP_INSN1): New defines. + (sparc64_linux_sigtramp_start, sparc64_linux_sigtramp_p, + sparc64_linux_sigtramp_frame_cache, + sparc64_linux_sigtramp_frame_this_id, + sparc64_linux_sigtramp_frame_prev_register, + sparc64_linux_sigtramp_frame_sniffer): New functions. + (sparc64_linux_sigtramp_frame_unwind): New frame unwinder. + (sparc64_linux_init_abi): Register sigtramp frame sniffer. + * Makefile.in (sparc64-linux-tdep.o): Update dependencies. + 2005-04-20 Mark Mitchell * configure.ac: On MinGW, define USE_WIN32API and link with diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 0bc7c878c94..abfec491843 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2565,8 +2565,10 @@ sparc64fbsd-tdep.o: sparc64fbsd-tdep.c $(defs_h) $(frame_h) \ $(sparc64_tdep_h) $(solib_svr4_h) sparc64-linux-nat.o: sparc64-linux-nat.c $(defs_h) $(sparc64_tdep_h) \ $(sparc_nat_h) -sparc64-linux-tdep.o: sparc64-linux-tdep.c $(defs_h) $(gdbarch_h) $(osabi_h) \ - $(solib_svr4_h) $(sparc64_tdep_h) +sparc64-linux-tdep.o: sparc64-linux-tdep.c $(defs_h) $(frame_h) \ + $(frame_unwind_h) $(gdbarch_h) $(osabi_h) $(solib_svr4_h) \ + $(symtab_h) $(trad_frame_h) $(gdb_assert_h) $(gdb_string_h) \ + $(sparc64_tdep_h) sparc64-nat.o: sparc64-nat.c $(defs_h) $(gdbarch_h) $(sparc64_tdep_h) \ $(sparc_nat_h) sparc64nbsd-nat.o: sparc64nbsd-nat.c $(defs_h) $(regcache_h) $(target_h) \ diff --git a/gdb/sparc-linux-tdep.c b/gdb/sparc-linux-tdep.c index 36c0565e468..db403655245 100644 --- a/gdb/sparc-linux-tdep.c +++ b/gdb/sparc-linux-tdep.c @@ -144,16 +144,17 @@ sparc32_linux_sigtramp_p (struct frame_info *next_frame) find_pc_partial_function (pc, &name, NULL, NULL); /* If we have NAME, we can optimize the search. The trampolines are - named __restore and __restore_rt. However, they aren't dynamically - exported from the shared C library, so the trampoline may appear to - be part of the preceding function. This should always be sigaction, - __sigaction, or __libc_sigaction (all aliases to the same function). */ + named __sigreturn_stub and __rt_sigreturn_stub. However, they + aren't dynamically exported from the shared C library, so the + trampoline may appear to be part of the preceding function. This + should always be sigaction, __sigaction, or __libc_sigaction (all + aliases to the same function). */ if (name == NULL || strstr (name, "sigaction") != NULL) return (sparc32_linux_sigtramp_start (next_frame) != 0 || sparc32_linux_rt_sigtramp_start (next_frame) != 0); - return (strcmp ("__restore", name) == 0 - || strcmp ("__restore_rt", name) == 0); + return (strcmp ("__sigreturn_stub", name) == 0 + || strcmp ("__rt_sigreturn_stub", name) == 0); } static struct sparc_frame_cache * @@ -192,6 +193,8 @@ sparc32_linux_sigtramp_frame_cache (struct frame_info *next_frame, cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + /* Offsets from */ + cache->saved_regs[SPARC32_PSR_REGNUM].addr = sigcontext_addr + 0; cache->saved_regs[SPARC32_PC_REGNUM].addr = sigcontext_addr + 4; cache->saved_regs[SPARC32_NPC_REGNUM].addr = sigcontext_addr + 8; diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c index 45c01939779..0047625b1c9 100644 --- a/gdb/sparc64-linux-tdep.c +++ b/gdb/sparc64-linux-tdep.c @@ -20,17 +20,194 @@ Boston, MA 02111-1307, USA. */ #include "defs.h" +#include "frame.h" +#include "frame-unwind.h" #include "gdbarch.h" #include "osabi.h" #include "solib-svr4.h" +#include "symtab.h" +#include "trad-frame.h" + +#include "gdb_assert.h" +#include "gdb_string.h" #include "sparc64-tdep.h" +/* The instruction sequence for RT signals is + mov __NR_rt_sigreturn, %g1 ! hex: 0x82102065 + ta 0x6d ! hex: 0x91d0206d + + The effect is to call the system call rt_sigreturn. + Note that 64-bit binaries only use this RT signal return method. */ + +#define LINUX64_RT_SIGTRAMP_INSN0 0x82102065 +#define LINUX64_RT_SIGTRAMP_INSN1 0x91d0206d + +/* If PC is in a sigtramp routine consisting of the instructions + LINUX64_RT_SIGTRAMP_INSN0 and LINUX64_RT_SIGTRAMP_INSN1, return + the address of the start of the routine. Otherwise, return 0. */ + +static CORE_ADDR +sparc64_linux_sigtramp_start (struct frame_info *next_frame) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + ULONGEST word0, word1; + unsigned char buf[8]; /* Two instructions. */ + + /* We only recognize a signal trampoline if PC is at the start of + one of the instructions. We optimize for finding the PC at the + start of the instruction sequence, as will be the case when the + trampoline is not the first frame on the stack. We assume that + in the case where the PC is not at the start of the instruction + sequence, there will be a few trailing readable bytes on the + stack. */ + + if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf)) + return 0; + + word0 = extract_unsigned_integer (buf, 4); + if (word0 != LINUX64_RT_SIGTRAMP_INSN0) + { + if (word0 != LINUX64_RT_SIGTRAMP_INSN1) + return 0; + + pc -= 4; + if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf)) + return 0; + + word0 = extract_unsigned_integer (buf, 4); + } + + word1 = extract_unsigned_integer (buf + 4, 4); + if (word0 != LINUX64_RT_SIGTRAMP_INSN0 + || word1 != LINUX64_RT_SIGTRAMP_INSN1) + return 0; + + return pc; +} + +static int +sparc64_linux_sigtramp_p (struct frame_info *next_frame) +{ + CORE_ADDR pc = frame_pc_unwind (next_frame); + char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + + /* If we have NAME, we can optimize the search. The trampolines is + named __rt_sigreturn_stub. However, is isn't dynamically exported + from the shared C library, so the trampoline may appear to be part + of the preceding function. This should always be sigaction, + __sigaction, or __libc_sigaction (all aliases to the same function). */ + if (name == NULL || strstr (name, "sigaction") != NULL) + return (sparc64_linux_sigtramp_start (next_frame) != 0); + + return (strcmp ("__rt_sigreturn_stub", name) == 0); +} + +static struct sparc_frame_cache * +sparc64_linux_sigtramp_frame_cache (struct frame_info *next_frame, + void **this_cache) +{ + struct sparc_frame_cache *cache; + CORE_ADDR sigcontext_addr, addr; + int regnum; + + if (*this_cache) + return *this_cache; + + cache = sparc_frame_cache (next_frame, this_cache); + gdb_assert (cache == *this_cache); + + regnum = SPARC_SP_REGNUM; + cache->base = frame_unwind_register_unsigned (next_frame, regnum); + if (cache->base & 1) + cache->base += BIAS; + + regnum = SPARC_O1_REGNUM; + sigcontext_addr = frame_unwind_register_unsigned (next_frame, regnum); + + /* If this is a RT signal trampoline, adjust SIGCONTEXT_ADDR + accordingly. */ + addr = sparc64_linux_sigtramp_start (next_frame); + if (addr) + sigcontext_addr += 128; + else + addr = frame_func_unwind (next_frame); + + cache->pc = addr; + + cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + /* Offsets from */ + + /* Since %g0 is always zero, keep the identity encoding. */ + for (addr = sigcontext_addr + 8, regnum = SPARC_G1_REGNUM; + regnum <= SPARC_O7_REGNUM; regnum++, addr += 8) + cache->saved_regs[regnum].addr = addr; + + cache->saved_regs[SPARC64_STATE_REGNUM].addr = addr + 0; + cache->saved_regs[SPARC64_PC_REGNUM].addr = addr + 8; + cache->saved_regs[SPARC64_NPC_REGNUM].addr = addr + 16; + cache->saved_regs[SPARC64_Y_REGNUM].addr = addr + 24; + cache->saved_regs[SPARC64_FPRS_REGNUM].addr = addr + 28; + + for (regnum = SPARC_L0_REGNUM, addr = cache->base; + regnum <= SPARC_I7_REGNUM; regnum++, addr += 8) + cache->saved_regs[regnum].addr = addr; + + return cache; +} + +static void +sparc64_linux_sigtramp_frame_this_id (struct frame_info *next_frame, + void **this_cache, + struct frame_id *this_id) +{ + struct sparc_frame_cache *cache = + sparc64_linux_sigtramp_frame_cache (next_frame, this_cache); + + (*this_id) = frame_id_build (cache->base, cache->pc); +} + +static void +sparc64_linux_sigtramp_frame_prev_register (struct frame_info *next_frame, + void **this_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, + CORE_ADDR *addrp, + int *realnump, void *valuep) +{ + struct sparc_frame_cache *cache = + sparc64_linux_sigtramp_frame_cache (next_frame, this_cache); + + trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, valuep); +} + +static const struct frame_unwind sparc64_linux_sigtramp_frame_unwind = +{ + SIGTRAMP_FRAME, + sparc64_linux_sigtramp_frame_this_id, + sparc64_linux_sigtramp_frame_prev_register +}; + +static const struct frame_unwind * +sparc64_linux_sigtramp_frame_sniffer (struct frame_info *next_frame) +{ + if (sparc64_linux_sigtramp_p (next_frame)) + return &sparc64_linux_sigtramp_frame_unwind; + + return NULL; +} + static void sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + frame_unwind_append_sniffer (gdbarch, sparc64_linux_sigtramp_frame_sniffer); + /* GNU/Linux is very similar to Solaris ... */ sparc64_sol2_init_abi (info, gdbarch); -- 2.39.5