* sparc-linux-tdep.c (sparc32_linux_sigframe_init): New function.

(sparc32_linux_sigframe, sparc32_linux_rt_sigframe): New tramp_frames.
	(sparc_linux_sigtramp_start, sparc32_linux_sigtramp_start,
	sparc32_linux_rt_sigtramp_start, sparc32_linux_sigtramp_p,
	sparc32_linux_sigtramp_frame_cache,
	sparc32_linux_sigtramp_frame_this_id,
	sparc32_linux_sigtramp_frame_prev_register,
	sparc32_linux_sigtramp_frame_unwind,
	sparc32_linux_sigtramp_frame_sniffer): Delete.
	(sparc32_linux_init_abi): Register new tramp unwinders.  Kill
	register of old sigtramp sniffer.
	* sparc64-linux-tdep.c (sparc64_linux_sigframe_init): New
	function.
	(sparc64_linux_rt_sigframe): New tramp frame.
	(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_unwind,
	sparc64_linux_sigtramp_frame_sniffer): Delete.
	(sparc64_linux_init_abi): Register new tramp unwinders.  Kill
	register of old sigtramp sniffer.
	Makefile.in (sparc64-linux-tdep.o): Update dependencies.
	(sparc-linux-tdep.o): Likewise.
This commit is contained in:
David S. Miller 2005-04-21 22:04:04 +00:00
parent 401e7faf6a
commit 81f726abf0
4 changed files with 136 additions and 324 deletions

View File

@ -1,3 +1,30 @@
2005-04-21 David S. Miller <davem@davemloft.net>
* sparc-linux-tdep.c (sparc32_linux_sigframe_init): New function.
(sparc32_linux_sigframe, sparc32_linux_rt_sigframe): New tramp_frames.
(sparc_linux_sigtramp_start, sparc32_linux_sigtramp_start,
sparc32_linux_rt_sigtramp_start, sparc32_linux_sigtramp_p,
sparc32_linux_sigtramp_frame_cache,
sparc32_linux_sigtramp_frame_this_id,
sparc32_linux_sigtramp_frame_prev_register,
sparc32_linux_sigtramp_frame_unwind,
sparc32_linux_sigtramp_frame_sniffer): Delete.
(sparc32_linux_init_abi): Register new tramp unwinders. Kill
register of old sigtramp sniffer.
* sparc64-linux-tdep.c (sparc64_linux_sigframe_init): New
function.
(sparc64_linux_rt_sigframe): New tramp frame.
(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_unwind,
sparc64_linux_sigtramp_frame_sniffer): Delete.
(sparc64_linux_init_abi): Register new tramp unwinders. Kill
register of old sigtramp sniffer.
Makefile.in (sparc64-linux-tdep.o): Update dependencies.
(sparc-linux-tdep.o): Likewise.
2005-04-21 Mark Kettenis <kettenis@gnu.org>
* ser-base.c: Include "gdb_string.h".

View File

@ -2567,7 +2567,7 @@ 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) $(frame_h) \
$(frame_unwind_h) $(gdbarch_h) $(osabi_h) $(solib_svr4_h) \
$(symtab_h) $(trad_frame_h) $(gdb_assert_h) $(gdb_string_h) \
$(symtab_h) $(trad_frame_h) \
$(sparc64_tdep_h)
sparc64-nat.o: sparc64-nat.c $(defs_h) $(gdbarch_h) $(sparc64_tdep_h) \
$(sparc_nat_h)
@ -2590,8 +2590,8 @@ sparc64-tdep.o: sparc64-tdep.c $(defs_h) $(arch_utils_h) $(floatformat_h) \
$(sparc64_tdep_h)
sparc-linux-tdep.o: sparc-linux-tdep.c $(defs_h) $(floatformat_h) $(frame_h) \
$(frame_unwind_h) $(gdbarch_h) $(gdbcore_h) $(osabi_h) $(regcache_h) \
$(solib_svr4_h) $(symtab_h) $(trad_frame_h) $(gdb_assert_h) \
$(gdb_string_h) $(sparc_tdep_h)
$(solib_svr4_h) $(symtab_h) $(trad_frame_h) \
$(sparc_tdep_h)
sparc-nat.o: sparc-nat.c $(defs_h) $(inferior_h) $(regcache_h) $(target_h) \
$(gdb_assert_h) $(gdb_string_h) $(gdb_wait_h) $(sparc_tdep_h) \
$(sparc_nat_h) $(inf_ptrace_h)

View File

@ -23,6 +23,7 @@
#include "floatformat.h"
#include "frame.h"
#include "frame-unwind.h"
#include "tramp-frame.h"
#include "gdbarch.h"
#include "gdbcore.h"
#include "osabi.h"
@ -31,12 +32,9 @@
#include "symtab.h"
#include "trad-frame.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "sparc-tdep.h"
/* Recognizing signal handler frames. */
/* Signal trampoline support. */
/* GNU/Linux has two flavors of signals. Normal signal handlers, and
"realtime" (RT) signals. The RT signals can provide additional
@ -69,195 +67,86 @@
/* The instruction sequence for RT signals is
mov __NR_rt_sigreturn, %g1 ! hex: 0x82102065
ta {0x10,0x6d} ! hex: 0x91d02010 or 0x91d0206d
ta {0x10,0x6d} ! hex: 0x91d02010
The effect is to call the system call rt_sigreturn. The trap number
is variable based upon whether this is a 32-bit or 64-bit sparc binary.
The effect is to call the system call rt_sigreturn.
Note that 64-bit binaries only use this RT signal return method. */
#define LINUX32_RT_SIGTRAMP_INSN0 0x82102065
#define LINUX32_RT_SIGTRAMP_INSN1 0x91d02010
/* If PC is in a sigtramp routine consisting of the instructions INSN0
and INSN1, return the address of the start of the routine.
Otherwise, return 0. */
static void sparc32_linux_sigframe_init (const struct tramp_frame *self,
struct frame_info *next_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func);
CORE_ADDR
sparc_linux_sigtramp_start (struct frame_info *next_frame,
ULONGEST insn0, ULONGEST insn1)
static const struct tramp_frame sparc32_linux_sigframe = {
SIGTRAMP_FRAME,
4,
{
{ LINUX32_SIGTRAMP_INSN0, -1 },
{ LINUX32_SIGTRAMP_INSN1, -1 },
{ TRAMP_SENTINEL_INSN, -1 }
},
sparc32_linux_sigframe_init
};
static const struct tramp_frame sparc32_linux_rt_sigframe = {
SIGTRAMP_FRAME,
4,
{
{ LINUX32_RT_SIGTRAMP_INSN0, -1 },
{ LINUX32_RT_SIGTRAMP_INSN1, -1 },
{ TRAMP_SENTINEL_INSN, -1 }
},
sparc32_linux_sigframe_init
};
static void
sparc32_linux_sigframe_init (const struct tramp_frame *self,
struct frame_info *next_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
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 != insn0)
{
if (word0 != 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 != insn0 || word1 != insn1)
return 0;
return pc;
}
static CORE_ADDR
sparc32_linux_sigtramp_start (struct frame_info *next_frame)
{
return sparc_linux_sigtramp_start (next_frame, LINUX32_SIGTRAMP_INSN0,
LINUX32_SIGTRAMP_INSN1);
}
static CORE_ADDR
sparc32_linux_rt_sigtramp_start (struct frame_info *next_frame)
{
return sparc_linux_sigtramp_start (next_frame, LINUX32_RT_SIGTRAMP_INSN0,
LINUX32_RT_SIGTRAMP_INSN1);
}
static int
sparc32_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 are
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 ("__sigreturn_stub", name) == 0
|| strcmp ("__rt_sigreturn_stub", name) == 0);
}
static struct sparc_frame_cache *
sparc32_linux_sigtramp_frame_cache (struct frame_info *next_frame,
void **this_cache)
{
struct sparc_frame_cache *cache;
CORE_ADDR sigcontext_addr, addr;
CORE_ADDR base, addr;
int regnum;
if (*this_cache)
return *this_cache;
cache = sparc32_frame_cache (next_frame, this_cache);
gdb_assert (cache == *this_cache);
/* ??? What about signal trampolines that aren't frameless? */
regnum = SPARC_SP_REGNUM;
cache->base = frame_unwind_register_unsigned (next_frame, regnum);
regnum = SPARC_O1_REGNUM;
sigcontext_addr = frame_unwind_register_unsigned (next_frame, regnum);
addr = sparc32_linux_sigtramp_start (next_frame);
if (addr == 0)
{
/* If this is a RT signal trampoline, adjust SIGCONTEXT_ADDR
accordingly. */
addr = sparc32_linux_rt_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);
base = frame_unwind_register_unsigned (next_frame, SPARC_O1_REGNUM);
if (self == &sparc32_linux_rt_sigframe)
base += 128;
/* Offsets from <bits/sigcontext.h> */
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;
cache->saved_regs[SPARC32_Y_REGNUM].addr = sigcontext_addr + 12;
trad_frame_set_reg_addr (this_cache, SPARC32_PSR_REGNUM, base + 0x00);
trad_frame_set_reg_addr (this_cache, SPARC32_PC_REGNUM, base + 0x04);
trad_frame_set_reg_addr (this_cache, SPARC32_NPC_REGNUM, base + 0x08);
trad_frame_set_reg_addr (this_cache, SPARC32_Y_REGNUM, base + 0x0c);
/* Since %g0 is always zero, keep the identity encoding. */
for (regnum = SPARC_G1_REGNUM, addr = sigcontext_addr + 20;
regnum <= SPARC_O7_REGNUM; regnum++, addr += 4)
cache->saved_regs[regnum].addr = addr;
addr = base + 0x14;
for (regnum = SPARC_G1_REGNUM; regnum <= SPARC_O7_REGNUM; regnum++)
{
trad_frame_set_reg_addr (this_cache, regnum, addr);
addr += 4;
}
for (regnum = SPARC_L0_REGNUM, addr = cache->base;
regnum <= SPARC_I7_REGNUM; regnum++, addr += 4)
cache->saved_regs[regnum].addr = addr;
return cache;
base = addr = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
{
trad_frame_set_reg_addr (this_cache, regnum, addr);
addr += 4;
}
trad_frame_set_id (this_cache, frame_id_build (base, func));
}
static void
sparc32_linux_sigtramp_frame_this_id (struct frame_info *next_frame,
void **this_cache,
struct frame_id *this_id)
{
struct sparc_frame_cache *cache =
sparc32_linux_sigtramp_frame_cache (next_frame, this_cache);
(*this_id) = frame_id_build (cache->base, cache->pc);
}
static void
sparc32_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 =
sparc32_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 sparc32_linux_sigtramp_frame_unwind =
{
SIGTRAMP_FRAME,
sparc32_linux_sigtramp_frame_this_id,
sparc32_linux_sigtramp_frame_prev_register
};
static const struct frame_unwind *
sparc32_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
if (sparc32_linux_sigtramp_p (next_frame))
return &sparc32_linux_sigtramp_frame_unwind;
return NULL;
}
static void
sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
tramp_frame_prepend_unwinder (gdbarch, &sparc32_linux_sigframe);
tramp_frame_prepend_unwinder (gdbarch, &sparc32_linux_rt_sigframe);
/* GNU/Linux is very similar to Solaris ... */
sparc32_sol2_init_abi (info, gdbarch);
@ -268,8 +157,6 @@ sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_long_double_bit (gdbarch, 64);
set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
frame_unwind_append_sniffer (gdbarch, sparc32_linux_sigtramp_frame_sniffer);
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);

View File

@ -22,15 +22,13 @@
#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "tramp-frame.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
@ -43,162 +41,62 @@
#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)
static void sparc64_linux_sigframe_init (const struct tramp_frame *self,
struct frame_info *next_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func);
static const struct tramp_frame sparc64_linux_rt_sigframe = {
SIGTRAMP_FRAME,
4,
{
{ LINUX64_RT_SIGTRAMP_INSN0, -1 },
{ LINUX64_RT_SIGTRAMP_INSN1, -1 },
{ TRAMP_SENTINEL_INSN, -1 }
},
sparc64_linux_sigframe_init
};
static void
sparc64_linux_sigframe_init (const struct tramp_frame *self,
struct frame_info *next_frame,
struct trad_frame_cache *this_cache,
CORE_ADDR func)
{
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;
CORE_ADDR base, 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);
base = frame_unwind_register_unsigned (next_frame, SPARC_O1_REGNUM);
base += 128;
/* Offsets from <bits/sigcontext.h> */
/* 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;
addr = base + 0x08;
for (regnum = SPARC_G1_REGNUM; regnum <= SPARC_O7_REGNUM; regnum++)
{
trad_frame_set_reg_addr (this_cache, regnum, addr);
addr += 8;
}
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;
trad_frame_set_reg_addr (this_cache, SPARC64_STATE_REGNUM, addr + 0x00);
trad_frame_set_reg_addr (this_cache, SPARC64_PC_REGNUM, addr + 0x08);
trad_frame_set_reg_addr (this_cache, SPARC64_NPC_REGNUM, addr + 0x10);
trad_frame_set_reg_addr (this_cache, SPARC64_Y_REGNUM, addr + 0x18);
trad_frame_set_reg_addr (this_cache, SPARC64_FPRS_REGNUM, addr + 0x1c);
for (regnum = SPARC_L0_REGNUM, addr = cache->base;
regnum <= SPARC_I7_REGNUM; regnum++, addr += 8)
cache->saved_regs[regnum].addr = addr;
addr = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
if (addr & 1)
addr += BIAS;
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;
base = addr;
for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
{
trad_frame_set_reg_addr (this_cache, regnum, addr);
addr += 8;
}
trad_frame_set_id (this_cache, frame_id_build (base, func));
}
static void
@ -206,7 +104,7 @@ 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);
tramp_frame_prepend_unwinder (gdbarch, &sparc64_linux_rt_sigframe);
/* GNU/Linux is very similar to Solaris ... */
sparc64_sol2_init_abi (info, gdbarch);