2003-04-08 Elena Zannoni <ezannoni@redhat.com>
[deliverable/binutils-gdb.git] / gdb / x86-64-linux-tdep.c
index ac41daa88493787eea8df1ffe74977f3df5f7b59..932e6d6f01b1517253a872ca8b404f96b09d5378 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GNU/Linux running on x86-64, for GDB.
 
-   Copyright 2001 Free Software Foundation, Inc.
+   Copyright 2001, 2003 Free Software Foundation, Inc.
 
    Contributed by Jiri Smid, SuSE Labs.
 
@@ -28,6 +28,7 @@
 #include "regcache.h"
 #include "x86-64-tdep.h"
 #include "dwarf2cfi.h"
+#include "osabi.h"
 
 #define LINUX_SIGTRAMP_INSN0 (0x48)    /* mov $NNNNNNNN,%rax */
 #define LINUX_SIGTRAMP_OFFSET0 (0)
 #define LINUX_SIGTRAMP_OFFSET1 (7)
 
 static const unsigned char linux_sigtramp_code[] = {
-  LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x89, 0x00, 0x00, 0x00,    /*  mov $0x89,%rax */
-  LINUX_SIGTRAMP_INSN1, 0x05   /* syscall */
+  /*  mov $__NR_rt_sigreturn,%rax */
+  LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
+  /* syscall */
+  LINUX_SIGTRAMP_INSN1, 0x05
 };
 
 #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
@@ -68,32 +71,37 @@ x86_64_linux_sigtramp_start (CORE_ADDR pc)
   return pc;
 }
 
-#define LINUX_SIGINFO_SIZE 128
+#define LINUX_SIGINFO_SIZE 0
 
 /* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
-#define LINUX_UCONTEXT_SIGCONTEXT_OFFSET (36)
+#define LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
+
+/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>.  */
+#define LINUX_SIGCONTEXT_PC_OFFSET 128
+#define LINUX_SIGCONTEXT_FP_OFFSET 120
 
 /* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
    address of the associated sigcontext structure.  */
-CORE_ADDR
+static CORE_ADDR
 x86_64_linux_sigcontext_addr (struct frame_info *frame)
 {
   CORE_ADDR pc;
+  ULONGEST rsp;
 
-  pc = x86_64_linux_sigtramp_start (frame->pc);
+  pc = x86_64_linux_sigtramp_start (get_frame_pc (frame));
   if (pc)
     {
-      if (frame->next)
+      if (get_next_frame (frame))
        /* 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. */
-       return frame->next->frame + LINUX_SIGINFO_SIZE +
+       return get_frame_base (get_next_frame (frame)) + LINUX_SIGINFO_SIZE +
          LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
 
 
       /* This is the top frame. */
-      return read_register (SP_REGNUM) + LINUX_SIGINFO_SIZE +
-       LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+      rsp = read_register (SP_REGNUM);
+      return rsp + LINUX_SIGINFO_SIZE + LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
 
     }
 
@@ -101,13 +109,10 @@ x86_64_linux_sigcontext_addr (struct frame_info *frame)
   return 0;
 }
 
-/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>.  */
-#define LINUX_SIGCONTEXT_PC_OFFSET (136)
-
 /* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
    saved program counter.  */
 
-CORE_ADDR
+static CORE_ADDR
 x86_64_linux_sigtramp_saved_pc (struct frame_info *frame)
 {
   CORE_ADDR addr;
@@ -121,7 +126,7 @@ x86_64_linux_sigtramp_saved_pc (struct frame_info *frame)
 CORE_ADDR
 x86_64_linux_saved_pc_after_call (struct frame_info *frame)
 {
-  if (frame->signal_handler_caller)
+  if ((get_frame_type (frame) == SIGTRAMP_FRAME))
     return x86_64_linux_sigtramp_saved_pc (frame);
 
   return read_memory_integer (read_register (SP_REGNUM), 8);
@@ -131,7 +136,75 @@ x86_64_linux_saved_pc_after_call (struct frame_info *frame)
 CORE_ADDR
 x86_64_linux_frame_saved_pc (struct frame_info *frame)
 {
-  if (frame->signal_handler_caller)
+  if ((get_frame_type (frame) == SIGTRAMP_FRAME))
     return x86_64_linux_sigtramp_saved_pc (frame);
   return cfi_get_ra (frame);
 }
+
+/* Return whether PC is in a GNU/Linux sigtramp routine.  */
+
+int
+x86_64_linux_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  if (name)
+    return strcmp ("__restore_rt", name) == 0;
+
+  return (x86_64_linux_sigtramp_start (pc) != 0);
+}
+
+CORE_ADDR
+x86_64_linux_frame_chain (struct frame_info *fi)
+{
+  ULONGEST addr;
+  CORE_ADDR fp, pc;
+
+  if (!(get_frame_type (fi) == SIGTRAMP_FRAME))
+    {
+      fp = cfi_frame_chain (fi);
+      if (fp)
+       return fp;
+      else
+       addr = get_frame_base (fi);
+    }
+  else
+    addr = get_frame_base (get_next_frame (fi));
+
+  addr += LINUX_SIGINFO_SIZE + LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+
+  fp = read_memory_integer (addr + LINUX_SIGCONTEXT_FP_OFFSET, 8) + 8;
+
+  return fp;
+}
+
+CORE_ADDR
+x86_64_init_frame_pc (int fromleaf, struct frame_info *fi)
+{
+  CORE_ADDR addr;
+
+  if (get_next_frame (fi)
+      && (get_frame_type (get_next_frame (fi)) == SIGTRAMP_FRAME))
+    {
+      addr = get_frame_base (get_next_frame (get_next_frame (fi)))
+       + LINUX_SIGINFO_SIZE + LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+      return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 8);
+    }
+  else
+    return cfi_init_frame_pc (fromleaf, fi);
+}
+\f
+
+static void
+x86_64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  x86_64_init_abi (info, gdbarch);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern void _initialize_x86_64_linux_tdep (void);
+
+void
+_initialize_x86_64_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_LINUX,
+                         x86_64_linux_init_abi);
+}
This page took 0.026496 seconds and 4 git commands to generate.