* arm-linux-tdep.c: Doc fixes.
(ARM_SIGCONTEXT_R0, ARM_UCONTEXT_SIGCONTEXT) (ARM_OLD_RT_SIGFRAME_SIGINFO, ARM_OLD_RT_SIGFRAME_UCONTEXT) (ARM_NEW_RT_SIGFRAME_UCONTEXT, ARM_NEW_SIGFRAME_MAGIC): New constants. (arm_linux_sigreturn_init, arm_linux_rt_sigreturn_init): Support the new signal frame layouts.
This commit is contained in:
parent
6e2c7fa123
commit
edfb1a2648
2 changed files with 82 additions and 9 deletions
|
@ -223,9 +223,10 @@ arm_linux_extract_return_value (struct type *type,
|
|||
#define ARM_LINUX_SIGRETURN_INSTR 0xef900077
|
||||
#define ARM_LINUX_RT_SIGRETURN_INSTR 0xef9000ad
|
||||
|
||||
/* For ARM EABI, recognize the pattern that glibc uses... alternatively,
|
||||
we could arrange to do this by function name, but they are not always
|
||||
exported. */
|
||||
/* For ARM EABI, the syscall number is not in the SWI instruction
|
||||
(instead it is loaded into r7). We recognize the pattern that
|
||||
glibc uses... alternatively, we could arrange to do this by
|
||||
function name, but they are not always exported. */
|
||||
#define ARM_SET_R7_SIGRETURN 0xe3a07077
|
||||
#define ARM_SET_R7_RT_SIGRETURN 0xe3a070ad
|
||||
#define ARM_EABI_SYSCALL 0xef000000
|
||||
|
@ -251,14 +252,67 @@ arm_linux_sigtramp_cache (struct frame_info *next_frame,
|
|||
trad_frame_set_id (this_cache, frame_id_build (sp, func));
|
||||
}
|
||||
|
||||
/* There are a couple of different possible stack layouts that
|
||||
we need to support.
|
||||
|
||||
Before version 2.6.18, the kernel used completely independent
|
||||
layouts for non-RT and RT signals. For non-RT signals the stack
|
||||
began directly with a struct sigcontext. For RT signals the stack
|
||||
began with two redundant pointers (to the siginfo and ucontext),
|
||||
and then the siginfo and ucontext.
|
||||
|
||||
As of version 2.6.18, the non-RT signal frame layout starts with
|
||||
a ucontext and the RT signal frame starts with a siginfo and then
|
||||
a ucontext. Also, the ucontext now has a designated save area
|
||||
for coprocessor registers.
|
||||
|
||||
For RT signals, it's easy to tell the difference: we look for
|
||||
pinfo, the pointer to the siginfo. If it has the expected
|
||||
value, we have an old layout. If it doesn't, we have the new
|
||||
layout.
|
||||
|
||||
For non-RT signals, it's a bit harder. We need something in one
|
||||
layout or the other with a recognizable offset and value. We can't
|
||||
use the return trampoline, because ARM usually uses SA_RESTORER,
|
||||
in which case the stack return trampoline is not filled in.
|
||||
We can't use the saved stack pointer, because sigaltstack might
|
||||
be in use. So for now we guess the new layout... */
|
||||
|
||||
/* There are three words (trap_no, error_code, oldmask) in
|
||||
struct sigcontext before r0. */
|
||||
#define ARM_SIGCONTEXT_R0 0xc
|
||||
|
||||
/* There are five words (uc_flags, uc_link, and three for uc_stack)
|
||||
in the ucontext_t before the sigcontext. */
|
||||
#define ARM_UCONTEXT_SIGCONTEXT 0x14
|
||||
|
||||
/* There are three elements in an rt_sigframe before the ucontext:
|
||||
pinfo, puc, and info. The first two are pointers and the third
|
||||
is a struct siginfo, with size 128 bytes. We could follow puc
|
||||
to the ucontext, but it's simpler to skip the whole thing. */
|
||||
#define ARM_OLD_RT_SIGFRAME_SIGINFO 0x8
|
||||
#define ARM_OLD_RT_SIGFRAME_UCONTEXT 0x88
|
||||
|
||||
#define ARM_NEW_RT_SIGFRAME_UCONTEXT 0x80
|
||||
|
||||
#define ARM_NEW_SIGFRAME_MAGIC 0x5ac3c35a
|
||||
|
||||
static void
|
||||
arm_linux_sigreturn_init (const struct tramp_frame *self,
|
||||
struct frame_info *next_frame,
|
||||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func)
|
||||
{
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
0x0c /* Offset to registers. */);
|
||||
CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
|
||||
ULONGEST uc_flags = read_memory_unsigned_integer (sp, 4);
|
||||
|
||||
if (uc_flags == ARM_NEW_SIGFRAME_MAGIC)
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
ARM_UCONTEXT_SIGCONTEXT
|
||||
+ ARM_SIGCONTEXT_R0);
|
||||
else
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
ARM_SIGCONTEXT_R0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -267,10 +321,19 @@ arm_linux_rt_sigreturn_init (const struct tramp_frame *self,
|
|||
struct trad_frame_cache *this_cache,
|
||||
CORE_ADDR func)
|
||||
{
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
0x88 /* Offset to ucontext_t. */
|
||||
+ 0x14 /* Offset to sigcontext. */
|
||||
+ 0x0c /* Offset to registers. */);
|
||||
CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
|
||||
ULONGEST pinfo = read_memory_unsigned_integer (sp, 4);
|
||||
|
||||
if (pinfo == sp + ARM_OLD_RT_SIGFRAME_SIGINFO)
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
ARM_OLD_RT_SIGFRAME_UCONTEXT
|
||||
+ ARM_UCONTEXT_SIGCONTEXT
|
||||
+ ARM_SIGCONTEXT_R0);
|
||||
else
|
||||
arm_linux_sigtramp_cache (next_frame, this_cache, func,
|
||||
ARM_NEW_RT_SIGFRAME_UCONTEXT
|
||||
+ ARM_UCONTEXT_SIGCONTEXT
|
||||
+ ARM_SIGCONTEXT_R0);
|
||||
}
|
||||
|
||||
static struct tramp_frame arm_linux_sigreturn_tramp_frame = {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue