#include "frame-unwind.h"
#include "tramp-frame.h"
-/* The following instructions are used in the signal trampoline code
- on GNU/Linux PPC. The kernel used to use magic syscalls 0x6666 and
- 0x7777 but now uses the sigreturn syscalls. We check for both. */
-#define INSTR_LI_R0_0x6666 0x38006666
-#define INSTR_LI_R0_0x7777 0x38007777
-#define INSTR_LI_R0_NR_sigreturn 0x38000077
-#define INSTR_LI_R0_NR_rt_sigreturn 0x380000AC
-
-#define INSTR_SC 0x44000002
-
-/* Since the *-tdep.c files are platform independent (i.e, they may be
- used to build cross platform debuggers), we can't include system
- headers. Therefore, details concerning the sigcontext structure
- must be painstakingly rerecorded. What's worse, if these details
- ever change in the header files, they'll have to be changed here
- as well. */
-
-/* __SIGNAL_FRAMESIZE from <asm/ptrace.h> */
-#define PPC_LINUX_SIGNAL_FRAMESIZE 64
-
-/* From <asm/sigcontext.h>, offsetof(struct sigcontext_struct, regs) == 0x1c */
-#define PPC_LINUX_REGS_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x1c)
-
-/* From <asm/sigcontext.h>,
- offsetof(struct sigcontext_struct, handler) == 0x14 */
-#define PPC_LINUX_HANDLER_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x14)
-
/* From <asm/ptrace.h>, values for PT_NIP, PT_R1, and PT_LNK */
#define PPC_LINUX_PT_R0 0
#define PPC_LINUX_PT_R1 1
#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
-static int ppc_linux_at_sigtramp_return_path (CORE_ADDR pc);
-
-/* Determine if pc is in a signal trampoline...
-
- Ha! That's not what this does at all. wait_for_inferior in
- infrun.c calls get_frame_type() in order to detect entry into a
- signal trampoline just after delivery of a signal. But on
- GNU/Linux, signal trampolines are used for the return path only.
- The kernel sets things up so that the signal handler is called
- directly.
-
- If we use in_sigtramp2() in place of in_sigtramp() (see below)
- we'll (often) end up with stop_pc in the trampoline and prev_pc in
- the (now exited) handler. The code there will cause a temporary
- breakpoint to be set on prev_pc which is not very likely to get hit
- again.
-
- If this is confusing, think of it this way... the code in
- wait_for_inferior() needs to be able to detect entry into a signal
- trampoline just after a signal is delivered, not after the handler
- has been run.
-
- So, we define in_sigtramp() below to return 1 if the following is
- true:
-
- 1) The previous frame is a real signal trampoline.
-
- - and -
-
- 2) pc is at the first or second instruction of the corresponding
- handler.
-
- Why the second instruction? It seems that wait_for_inferior()
- never sees the first instruction when single stepping. When a
- signal is delivered while stepping, the next instruction that
- would've been stepped over isn't, instead a signal is delivered and
- the first instruction of the handler is stepped over instead. That
- puts us on the second instruction. (I added the test for the first
- instruction long after the fact, just in case the observed behavior
- is ever fixed.) */
-
-int
-ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
-{
- CORE_ADDR lr;
- CORE_ADDR sp;
- CORE_ADDR tramp_sp;
- gdb_byte buf[4];
- CORE_ADDR handler;
-
- lr = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum);
- if (!ppc_linux_at_sigtramp_return_path (lr))
- return 0;
-
- sp = read_register (SP_REGNUM);
-
- if (target_read_memory (sp, buf, sizeof (buf)) != 0)
- return 0;
-
- tramp_sp = extract_unsigned_integer (buf, 4);
-
- if (target_read_memory (tramp_sp + PPC_LINUX_HANDLER_PTR_OFFSET, buf,
- sizeof (buf)) != 0)
- return 0;
-
- handler = extract_unsigned_integer (buf, 4);
-
- return (pc == handler || pc == handler + 4);
-}
-
-static int
-insn_is_sigreturn (unsigned long pcinsn)
-{
- switch(pcinsn)
- {
- case INSTR_LI_R0_0x6666:
- case INSTR_LI_R0_0x7777:
- case INSTR_LI_R0_NR_sigreturn:
- case INSTR_LI_R0_NR_rt_sigreturn:
- return 1;
- default:
- return 0;
- }
-}
-
-/*
- * The signal handler trampoline is on the stack and consists of exactly
- * two instructions. The easiest and most accurate way of determining
- * whether the pc is in one of these trampolines is by inspecting the
- * instructions. It'd be faster though if we could find a way to do this
- * via some simple address comparisons.
- */
-static int
-ppc_linux_at_sigtramp_return_path (CORE_ADDR pc)
-{
- gdb_byte buf[12];
- unsigned long pcinsn;
- if (target_read_memory (pc - 4, buf, sizeof (buf)) != 0)
- return 0;
-
- /* extract the instruction at the pc */
- pcinsn = extract_unsigned_integer (buf + 4, 4);
-
- return (
- (insn_is_sigreturn (pcinsn)
- && extract_unsigned_integer (buf + 8, 4) == INSTR_SC)
- ||
- (pcinsn == INSTR_SC
- && insn_is_sigreturn (extract_unsigned_integer (buf, 4))));
-}
static CORE_ADDR
ppc_linux_skip_trampoline_code (CORE_ADDR pc)