* i386-linux-nat.c: No need to #include "frame.h" any more.
authorJim Blandy <jimb@codesourcery.com>
Mon, 20 Mar 2000 20:38:29 +0000 (20:38 +0000)
committerJim Blandy <jimb@codesourcery.com>
Mon, 20 Mar 2000 20:38:29 +0000 (20:38 +0000)
(LINUX_SIGTRAMP_INSN0, LINUX_SIGTRAMP_OFFSET0,
LINUX_SIGTRAMP_INSN1, LINUX_SIGTRAMP_OFFSET1,
LINUX_SIGTRAMP_INSN2, LINUX_SIGTRAMP_OFFSET2, linux_sigtramp_code,
LINUX_SIGTRAMP_LEN, i386_linux_sigtramp_start,
LINUX_RT_SIGTRAMP_INSN0, LINUX_RT_SIGTRAMP_OFFSET0,
LINUX_RT_SIGTRAMP_INSN1, LINUX_RT_SIGTRAMP_OFFSET1,
linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN,
i386_linux_rt_sigtramp_start, i386_linux_in_sigtramp,
i386_linux_sigcontext_addr, LINUX_SIGCONTEXT_PC_OFFSET,
i386_linux_sigtramp_saved_pc, LINUX_SIGCONTEXT_SP_OFFSET,
i386_linux_sigtramp_saved_sp): Deleted.  Folks rightly pointed
out that these are target-dependent, and useful in non-native
configurations.  Moved to...
* i386-linux-tdep.c: ... Here, a new file.
* Makefile.in (ALLDEPFILES): Add i386-linux-tdep.c.
(i386-linux-tdep.o): New rule.
(i386-linux-nat.o): We no longer depend on frame.h.
* config/i386/linux.mt (TDEPFILES): Add i386-linux-tdep.o.

gdb/ChangeLog
gdb/Makefile.in
gdb/config/i386/linux.mt
gdb/i386-linux-nat.c
gdb/i386-linux-tdep.c [new file with mode: 0644]

index bd1b1427fd80681445080a4a48986687e73015f8..b715b301dd6c4c905a44f7dc0d1dc387fc607e27 100644 (file)
@@ -1,3 +1,25 @@
+2000-03-20  Jim Blandy  <jimb@redhat.com>
+
+       * i386-linux-nat.c: No need to #include "frame.h" any more.
+       (LINUX_SIGTRAMP_INSN0, LINUX_SIGTRAMP_OFFSET0,
+       LINUX_SIGTRAMP_INSN1, LINUX_SIGTRAMP_OFFSET1,
+       LINUX_SIGTRAMP_INSN2, LINUX_SIGTRAMP_OFFSET2, linux_sigtramp_code,
+       LINUX_SIGTRAMP_LEN, i386_linux_sigtramp_start,
+       LINUX_RT_SIGTRAMP_INSN0, LINUX_RT_SIGTRAMP_OFFSET0,
+       LINUX_RT_SIGTRAMP_INSN1, LINUX_RT_SIGTRAMP_OFFSET1,
+       linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN,
+       i386_linux_rt_sigtramp_start, i386_linux_in_sigtramp,
+       i386_linux_sigcontext_addr, LINUX_SIGCONTEXT_PC_OFFSET,
+       i386_linux_sigtramp_saved_pc, LINUX_SIGCONTEXT_SP_OFFSET,
+       i386_linux_sigtramp_saved_sp):  Deleted.  Folks rightly pointed
+       out that these are target-dependent, and useful in non-native
+       configurations.  Moved to...
+       * i386-linux-tdep.c: ... Here, a new file.
+       * Makefile.in (ALLDEPFILES): Add i386-linux-tdep.c.
+       (i386-linux-tdep.o): New rule.
+       (i386-linux-nat.o): We no longer depend on frame.h.
+       * config/i386/linux.mt (TDEPFILES): Add i386-linux-tdep.o.
+
 2000-03-04  Eli Zaretskii  <eliz@is.elta.co.il>
 
        * event-loop.c (top-level) [NO_FD_SET]: Deprecate this branch.
@@ -64,26 +86,6 @@ Mon Mar 20 17:33:32 2000  Andrew Cagney  <cagney@b1.cygnus.com>
        * gdb_wait.h (WSETSTOP): Pass the appropriate number of arguments
        to W_STOPCODE.
 
-       * i386-linux-nat.c: No need to #include "frame.h" any more.
-       (LINUX_SIGTRAMP_INSN0, LINUX_SIGTRAMP_OFFSET0,
-       LINUX_SIGTRAMP_INSN1, LINUX_SIGTRAMP_OFFSET1,
-       LINUX_SIGTRAMP_INSN2, LINUX_SIGTRAMP_OFFSET2, linux_sigtramp_code,
-       LINUX_SIGTRAMP_LEN, i386_linux_sigtramp_start,
-       LINUX_RT_SIGTRAMP_INSN0, LINUX_RT_SIGTRAMP_OFFSET0,
-       LINUX_RT_SIGTRAMP_INSN1, LINUX_RT_SIGTRAMP_OFFSET1,
-       linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN,
-       i386_linux_rt_sigtramp_start, i386_linux_in_sigtramp,
-       i386_linux_sigcontext_addr, LINUX_SIGCONTEXT_PC_OFFSET,
-       i386_linux_sigtramp_saved_pc, LINUX_SIGCONTEXT_SP_OFFSET,
-       i386_linux_sigtramp_saved_sp):  Deleted.  Folks rightly pointed
-       out that these are target-dependent, and useful in non-native
-       configurations.  Moved to...
-       * i386-linux-tdep.c: ... Here, a new file.
-       * Makefile.in (ALLDEPFILES): Add i386-linux-tdep.c.
-       (i386-linux-tdep.o): New rule.
-       (i386-linux-nat.o): We no longer depend on frame.h.
-       * config/i386/linux.mt (TDEPFILES): Add i386-linux-tdep.o.
-
        * solib.c (solib_add): Delete debugging code.
 
 2000-03-17  Mark Kettenis  <kettenis@gnu.org>
index 72441caa3de1406fca00fdd9477bdbca45c10e11..60464323897cb166364f29070b24b916a1c30630 100644 (file)
@@ -1063,6 +1063,7 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \
        i386-tdep.c i386b-nat.c i386mach-nat.c i386v-nat.c i386-linux-nat.c \
        i386aix-nat.c i386m3-nat.c i386v4-nat.c i386ly-tdep.c \
        i387-tdep.c \
+       i386-linux-tdep.c \
        i960-tdep.c \
        infptrace.c inftarg.c irix4-nat.c irix5-nat.c isi-xdep.c \
        lynx-nat.c m3-nat.c \
@@ -1395,7 +1396,10 @@ i386v-nat.o: i386v-nat.c $(floatformat_h) $(defs_h) $(gdbcore_h) \
        $(inferior_h) language.h target.h
 
 i386-linux-nat.o: i386-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
-       $(symtab_h) $(frame_h) symfile.h objfiles.h
+       $(symtab_h) symfile.h objfiles.h
+
+i386-linux-tdep.o: i386-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \
+       $(value_h)
 
 i386v4-nat.o: i386v4-nat.c $(defs_h)
 
index 66cc97dbde53a57479c0ed034a9be6ee8dc2208f..df17b18436975a706f51942b5f3eafee151afd07 100644 (file)
@@ -1,5 +1,5 @@
 # Target: Intel 386 running GNU/Linux
-TDEPFILES= i386-tdep.o i387-tdep.o
+TDEPFILES= i386-tdep.o i386-linux-tdep.o i387-tdep.o
 TM_FILE= tm-linux.h
 
 GDBSERVER_DEPFILES= low-linux.o
index bf5e821a27936e9a22f882006b1b0f702d4eac61..2e46ead746ca66c2a06db9d5f1cdd73f7c797e49 100644 (file)
@@ -23,7 +23,6 @@
 
 /* For i386_linux_skip_solib_resolver.  */
 #include "symtab.h"
-#include "frame.h"
 #include "symfile.h"
 #include "objfiles.h"
 
@@ -1043,263 +1042,6 @@ i386_linux_skip_solib_resolver (CORE_ADDR pc)
   return 0;
 }
 
-\f
-/* Recognizing signal handler frames.  */
-
-/* Linux has two flavors of signals.  Normal signal handlers, and
-   "realtime" (RT) signals.  The RT signals can provide additional
-   information to the signal handler if the SA_SIGINFO flag is set
-   when establishing a signal handler using `sigaction'.  It is not
-   unlikely that future versions of Linux will support SA_SIGINFO for
-   normal signals too.  */
-
-/* When the i386 Linux kernel calls a signal handler and the
-   SA_RESTORER flag isn't set, the return address points to a bit of
-   code on the stack.  This function returns whether the PC appears to
-   be within this bit of code.
-
-   The instruction sequence for normal signals is
-       pop    %eax
-       mov    $0x77,%eax
-       int    $0x80
-   or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
-
-   Checking for the code sequence should be somewhat reliable, because
-   the effect is to call the system call sigreturn.  This is unlikely
-   to occur anywhere other than a signal trampoline.
-
-   It kind of sucks that we have to read memory from the process in
-   order to identify a signal trampoline, but there doesn't seem to be
-   any other way.  The IN_SIGTRAMP macro in tm-linux.h arranges to
-   only call us if no function name could be identified, which should
-   be the case since the code is on the stack.
-
-   Detection of signal trampolines for handlers that set the
-   SA_RESTORER flag is in general not possible.  Unfortunately this is
-   what the GNU C Library has been doing for quite some time now.
-   However, as of version 2.1.2, the GNU C Library uses signal
-   trampolines (named __restore and __restore_rt) that are identical
-   to the ones used by the kernel.  Therefore, these trampolines are
-   supported too.  */
-
-#define LINUX_SIGTRAMP_INSN0 (0x58)    /* pop %eax */
-#define LINUX_SIGTRAMP_OFFSET0 (0)
-#define LINUX_SIGTRAMP_INSN1 (0xb8)    /* mov $NNNN,%eax */
-#define LINUX_SIGTRAMP_OFFSET1 (1)
-#define LINUX_SIGTRAMP_INSN2 (0xcd)    /* int */
-#define LINUX_SIGTRAMP_OFFSET2 (6)
-
-static const unsigned char linux_sigtramp_code[] =
-{
-  LINUX_SIGTRAMP_INSN0,                                        /* pop %eax */
-  LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00,                /* mov $0x77,%eax */
-  LINUX_SIGTRAMP_INSN2, 0x80                           /* int $0x80 */
-};
-
-#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
-
-/* If PC is in a sigtramp routine, return the address of the start of
-   the routine.  Otherwise, return 0.  */
-
-static CORE_ADDR
-i386_linux_sigtramp_start (CORE_ADDR pc)
-{
-  unsigned char buf[LINUX_SIGTRAMP_LEN];
-
-  /* We only recognize a signal trampoline if PC is at the start of
-     one of the three instructions.  We optimize for finding the PC at
-     the start, 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 (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
-    return 0;
-
-  if (buf[0] != LINUX_SIGTRAMP_INSN0)
-    {
-      int adjust;
-
-      switch (buf[0])
-       {
-       case LINUX_SIGTRAMP_INSN1:
-         adjust = LINUX_SIGTRAMP_OFFSET1;
-         break;
-       case LINUX_SIGTRAMP_INSN2:
-         adjust = LINUX_SIGTRAMP_OFFSET2;
-         break;
-       default:
-         return 0;
-       }
-
-      pc -= adjust;
-
-      if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
-       return 0;
-    }
-
-  if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
-    return 0;
-
-  return pc;
-}
-
-/* This function does the same for RT signals.  Here the instruction
-   sequence is
-       mov    $0xad,%eax
-       int    $0x80
-   or 0xb8 0xad 0x00 0x00 0x00 0xcd 0x80.
-
-   The effect is to call the system call rt_sigreturn.  */
-
-#define LINUX_RT_SIGTRAMP_INSN0 (0xb8) /* mov $NNNN,%eax */
-#define LINUX_RT_SIGTRAMP_OFFSET0 (0)
-#define LINUX_RT_SIGTRAMP_INSN1 (0xcd) /* int */
-#define LINUX_RT_SIGTRAMP_OFFSET1 (5)
-
-static const unsigned char linux_rt_sigtramp_code[] =
-{
-  LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00,     /* mov $0xad,%eax */
-  LINUX_RT_SIGTRAMP_INSN1, 0x80                                /* int $0x80 */
-};
-
-#define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
-
-/* If PC is in a RT sigtramp routine, return the address of the start
-   of the routine.  Otherwise, return 0.  */
-
-static CORE_ADDR
-i386_linux_rt_sigtramp_start (CORE_ADDR pc)
-{
-  unsigned char buf[LINUX_RT_SIGTRAMP_LEN];
-
-  /* We only recognize a signal trampoline if PC is at the start of
-     one of the two instructions.  We optimize for finding the PC at
-     the start, 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 (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
-    return 0;
-
-  if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
-    {
-      if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
-       return 0;
-
-      pc -= LINUX_RT_SIGTRAMP_OFFSET1;
-
-      if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
-       return 0;
-    }
-
-  if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
-    return 0;
-
-  return pc;
-}
-
-/* Return whether PC is in a Linux sigtramp routine.  */
-
-int
-i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
-{
-  if (name)
-    return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
-  
-  return (i386_linux_sigtramp_start (pc) != 0
-         || i386_linux_rt_sigtramp_start (pc) != 0);
-}
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the address
-   of the associated sigcontext structure.  */
-
-CORE_ADDR
-i386_linux_sigcontext_addr (struct frame_info *frame)
-{
-  CORE_ADDR pc;
-
-  pc = i386_linux_sigtramp_start (frame->pc);
-  if (pc)
-    {
-      CORE_ADDR sp;
-
-      if (frame->next)
-       /* If this isn't the top frame, the next frame must be for the
-          signal handler itself.  The sigcontext structure lives on
-          the stack, right after the signum argument.  */
-       return frame->next->frame + 12;
-
-      /* This is the top frame.  We'll have to find the address of the
-        sigcontext structure by looking at the stack pointer.  Keep
-        in mind that the first instruction of the sigtramp code is
-        "pop %eax".  If the PC is at this instruction, adjust the
-        returned value accordingly.  */
-      sp = read_register (SP_REGNUM);
-      if (pc == frame->pc)
-       return sp + 4;
-      return sp;
-    }
-
-  pc = i386_linux_rt_sigtramp_start (frame->pc);
-  if (pc)
-    {
-      if (frame->next)
-       /* If this isn't the top frame, the next frame must be for the
-          signal handler itself.  The sigcontext structure is part of
-          the user context.  A pointer to the user context is passed
-          as the third argument to the signal handler.  */
-       return read_memory_integer (frame->next->frame + 16, 4) + 20;
-
-      /* This is the top frame.  Again, use the stack pointer to find
-        the address of the sigcontext structure.  */
-      return read_memory_integer (read_register (SP_REGNUM) + 8, 4) + 20;
-    }
-
-  error ("Couldn't recognize signal trampoline.");
-  return 0;
-}
-
-/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>.  */
-#define LINUX_SIGCONTEXT_PC_OFFSET (56)
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the saved
-   program counter.  */
-
-CORE_ADDR
-i386_linux_sigtramp_saved_pc (struct frame_info *frame)
-{
-  CORE_ADDR addr;
-  addr = i386_linux_sigcontext_addr (frame);
-  return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
-}
-
-/* Offset to saved SP in sigcontext, from <asm/sigcontext.h>.  */
-#define LINUX_SIGCONTEXT_SP_OFFSET (28)
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the saved
-   stack pointer.  */
-
-CORE_ADDR
-i386_linux_sigtramp_saved_sp (struct frame_info *frame)
-{
-  CORE_ADDR addr;
-  addr = i386_linux_sigcontext_addr (frame);
-  return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
-}
-
-/* Immediately after a function call, return the saved pc.  */
-
-CORE_ADDR
-i386_linux_saved_pc_after_call (struct frame_info *frame)
-{
-  if (frame->signal_handler_caller)
-    return i386_linux_sigtramp_saved_pc (frame);
-
-  return read_memory_integer (read_register (SP_REGNUM), 4);
-}
-
 \f
 /* Register that we are able to handle Linux ELF core file formats.  */
 
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
new file mode 100644 (file)
index 0000000..38d6bcb
--- /dev/null
@@ -0,0 +1,281 @@
+/* Target-dependent code for Linux running on i386's, for GDB.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "frame.h"
+#include "value.h"
+
+\f
+/* Recognizing signal handler frames.  */
+
+/* Linux has two flavors of signals.  Normal signal handlers, and
+   "realtime" (RT) signals.  The RT signals can provide additional
+   information to the signal handler if the SA_SIGINFO flag is set
+   when establishing a signal handler using `sigaction'.  It is not
+   unlikely that future versions of Linux will support SA_SIGINFO for
+   normal signals too.  */
+
+/* When the i386 Linux kernel calls a signal handler and the
+   SA_RESTORER flag isn't set, the return address points to a bit of
+   code on the stack.  This function returns whether the PC appears to
+   be within this bit of code.
+
+   The instruction sequence for normal signals is
+       pop    %eax
+       mov    $0x77,%eax
+       int    $0x80
+   or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
+
+   Checking for the code sequence should be somewhat reliable, because
+   the effect is to call the system call sigreturn.  This is unlikely
+   to occur anywhere other than a signal trampoline.
+
+   It kind of sucks that we have to read memory from the process in
+   order to identify a signal trampoline, but there doesn't seem to be
+   any other way.  The IN_SIGTRAMP macro in tm-linux.h arranges to
+   only call us if no function name could be identified, which should
+   be the case since the code is on the stack.
+
+   Detection of signal trampolines for handlers that set the
+   SA_RESTORER flag is in general not possible.  Unfortunately this is
+   what the GNU C Library has been doing for quite some time now.
+   However, as of version 2.1.2, the GNU C Library uses signal
+   trampolines (named __restore and __restore_rt) that are identical
+   to the ones used by the kernel.  Therefore, these trampolines are
+   supported too.  */
+
+#define LINUX_SIGTRAMP_INSN0 (0x58)    /* pop %eax */
+#define LINUX_SIGTRAMP_OFFSET0 (0)
+#define LINUX_SIGTRAMP_INSN1 (0xb8)    /* mov $NNNN,%eax */
+#define LINUX_SIGTRAMP_OFFSET1 (1)
+#define LINUX_SIGTRAMP_INSN2 (0xcd)    /* int */
+#define LINUX_SIGTRAMP_OFFSET2 (6)
+
+static const unsigned char linux_sigtramp_code[] =
+{
+  LINUX_SIGTRAMP_INSN0,                                        /* pop %eax */
+  LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00,                /* mov $0x77,%eax */
+  LINUX_SIGTRAMP_INSN2, 0x80                           /* int $0x80 */
+};
+
+#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
+
+/* If PC is in a sigtramp routine, return the address of the start of
+   the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+i386_linux_sigtramp_start (CORE_ADDR pc)
+{
+  unsigned char buf[LINUX_SIGTRAMP_LEN];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the three instructions.  We optimize for finding the PC at
+     the start, 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 (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  if (buf[0] != LINUX_SIGTRAMP_INSN0)
+    {
+      int adjust;
+
+      switch (buf[0])
+       {
+       case LINUX_SIGTRAMP_INSN1:
+         adjust = LINUX_SIGTRAMP_OFFSET1;
+         break;
+       case LINUX_SIGTRAMP_INSN2:
+         adjust = LINUX_SIGTRAMP_OFFSET2;
+         break;
+       default:
+         return 0;
+       }
+
+      pc -= adjust;
+
+      if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+       return 0;
+    }
+
+  if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  return pc;
+}
+
+/* This function does the same for RT signals.  Here the instruction
+   sequence is
+       mov    $0xad,%eax
+       int    $0x80
+   or 0xb8 0xad 0x00 0x00 0x00 0xcd 0x80.
+
+   The effect is to call the system call rt_sigreturn.  */
+
+#define LINUX_RT_SIGTRAMP_INSN0 (0xb8) /* mov $NNNN,%eax */
+#define LINUX_RT_SIGTRAMP_OFFSET0 (0)
+#define LINUX_RT_SIGTRAMP_INSN1 (0xcd) /* int */
+#define LINUX_RT_SIGTRAMP_OFFSET1 (5)
+
+static const unsigned char linux_rt_sigtramp_code[] =
+{
+  LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00,     /* mov $0xad,%eax */
+  LINUX_RT_SIGTRAMP_INSN1, 0x80                                /* int $0x80 */
+};
+
+#define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
+
+/* If PC is in a RT sigtramp routine, return the address of the start
+   of the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+i386_linux_rt_sigtramp_start (CORE_ADDR pc)
+{
+  unsigned char buf[LINUX_RT_SIGTRAMP_LEN];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the two instructions.  We optimize for finding the PC at
+     the start, 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 (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
+    {
+      if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
+       return 0;
+
+      pc -= LINUX_RT_SIGTRAMP_OFFSET1;
+
+      if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+       return 0;
+    }
+
+  if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  return pc;
+}
+
+/* Return whether PC is in a Linux sigtramp routine.  */
+
+int
+i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  if (name)
+    return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
+  
+  return (i386_linux_sigtramp_start (pc) != 0
+         || i386_linux_rt_sigtramp_start (pc) != 0);
+}
+
+/* Assuming FRAME is for a Linux sigtramp routine, return the address
+   of the associated sigcontext structure.  */
+
+CORE_ADDR
+i386_linux_sigcontext_addr (struct frame_info *frame)
+{
+  CORE_ADDR pc;
+
+  pc = i386_linux_sigtramp_start (frame->pc);
+  if (pc)
+    {
+      CORE_ADDR sp;
+
+      if (frame->next)
+       /* If this isn't the top frame, the next frame must be for the
+          signal handler itself.  The sigcontext structure lives on
+          the stack, right after the signum argument.  */
+       return frame->next->frame + 12;
+
+      /* This is the top frame.  We'll have to find the address of the
+        sigcontext structure by looking at the stack pointer.  Keep
+        in mind that the first instruction of the sigtramp code is
+        "pop %eax".  If the PC is at this instruction, adjust the
+        returned value accordingly.  */
+      sp = read_register (SP_REGNUM);
+      if (pc == frame->pc)
+       return sp + 4;
+      return sp;
+    }
+
+  pc = i386_linux_rt_sigtramp_start (frame->pc);
+  if (pc)
+    {
+      if (frame->next)
+       /* If this isn't the top frame, the next frame must be for the
+          signal handler itself.  The sigcontext structure is part of
+          the user context.  A pointer to the user context is passed
+          as the third argument to the signal handler.  */
+       return read_memory_integer (frame->next->frame + 16, 4) + 20;
+
+      /* This is the top frame.  Again, use the stack pointer to find
+        the address of the sigcontext structure.  */
+      return read_memory_integer (read_register (SP_REGNUM) + 8, 4) + 20;
+    }
+
+  error ("Couldn't recognize signal trampoline.");
+  return 0;
+}
+
+/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>.  */
+#define LINUX_SIGCONTEXT_PC_OFFSET (56)
+
+/* Assuming FRAME is for a Linux sigtramp routine, return the saved
+   program counter.  */
+
+CORE_ADDR
+i386_linux_sigtramp_saved_pc (struct frame_info *frame)
+{
+  CORE_ADDR addr;
+  addr = i386_linux_sigcontext_addr (frame);
+  return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
+}
+
+/* Offset to saved SP in sigcontext, from <asm/sigcontext.h>.  */
+#define LINUX_SIGCONTEXT_SP_OFFSET (28)
+
+/* Assuming FRAME is for a Linux sigtramp routine, return the saved
+   stack pointer.  */
+
+CORE_ADDR
+i386_linux_sigtramp_saved_sp (struct frame_info *frame)
+{
+  CORE_ADDR addr;
+  addr = i386_linux_sigcontext_addr (frame);
+  return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
+}
+
+/* Immediately after a function call, return the saved pc.  */
+
+CORE_ADDR
+i386_linux_saved_pc_after_call (struct frame_info *frame)
+{
+  if (frame->signal_handler_caller)
+    return i386_linux_sigtramp_saved_pc (frame);
+
+  return read_memory_integer (read_register (SP_REGNUM), 4);
+}