* gdb/fileio.h: New file.
[deliverable/binutils-gdb.git] / gdb / i386-linux-tdep.c
index 9592decee1955f7ece8dea0c33a60aa7c2cbd610..6d284f1ea98e4d827bb5910bf797428b3c8ee578 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for GNU/Linux running on i386's, for GDB.
 
-   Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -25,6 +25,7 @@
 #include "value.h"
 #include "regcache.h"
 #include "inferior.h"
+#include "reggroups.h"
 
 /* For i386_linux_skip_solib_resolver.  */
 #include "symtab.h"
 
 #include "solib-svr4.h"                /* For struct link_map_offsets.  */
 
+#include "osabi.h"
+
+#include "i386-tdep.h"
+#include "i386-linux-tdep.h"
+
 /* Return the name of register REG.  */
 
-char *
+static const char *
 i386_linux_register_name (int reg)
 {
   /* Deal with the extra "orig_eax" pseudo register.  */
@@ -45,26 +51,19 @@ i386_linux_register_name (int reg)
   return i386_register_name (reg);
 }
 
-int
-i386_linux_register_byte (int reg)
+/* Return non-zero, when the register is in the corresponding register
+   group.  Put the LINUX_ORIG_EAX register in the system group.  */
+static int
+i386_linux_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+                               struct reggroup *group)
 {
-  /* Deal with the extra "orig_eax" pseudo register.  */
-  if (reg == I386_LINUX_ORIG_EAX_REGNUM)
-    return (i386_register_byte (I386_LINUX_ORIG_EAX_REGNUM - 1)
-           + i386_register_raw_size (I386_LINUX_ORIG_EAX_REGNUM - 1));
-
-  return i386_register_byte (reg);
+  if (regnum == I386_LINUX_ORIG_EAX_REGNUM)
+    return (group == system_reggroup
+           || group == save_reggroup
+           || group == restore_reggroup);
+  return i386_register_reggroup_p (gdbarch, regnum, group);
 }
 
-int
-i386_linux_register_raw_size (int reg)
-{
-  /* Deal with the extra "orig_eax" pseudo register.  */
-  if (reg == I386_LINUX_ORIG_EAX_REGNUM)
-    return 4;
-
-  return i386_register_raw_size (reg);
-}
 \f
 /* Recognizing signal handler frames.  */
 
@@ -82,7 +81,7 @@ i386_linux_register_raw_size (int reg)
 
    The instruction sequence for normal signals is
        pop    %eax
-       mov    $0x77,%eax
+       mov    $0x77, %eax
        int    $0x80
    or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
 
@@ -104,17 +103,17 @@ i386_linux_register_raw_size (int reg)
    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)
+#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_INSN1, 0x77, 0x00, 0x00, 0x00,                /* mov $0x77, %eax */
   LINUX_SIGTRAMP_INSN2, 0x80                           /* int $0x80 */
 };
 
@@ -168,20 +167,20 @@ i386_linux_sigtramp_start (CORE_ADDR pc)
 
 /* This function does the same for RT signals.  Here the instruction
    sequence is
-       mov    $0xad,%eax
+       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)
+#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_INSN0, 0xad, 0x00, 0x00, 0x00,     /* mov $0xad, %eax */
   LINUX_RT_SIGTRAMP_INSN1, 0x80                                /* int $0x80 */
 };
 
@@ -224,165 +223,75 @@ i386_linux_rt_sigtramp_start (CORE_ADDR pc)
 
 /* Return whether PC is in a GNU/Linux sigtramp routine.  */
 
-int
-i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
+static int
+i386_linux_pc_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);
+  /* If we have NAME, we can optimize the search.  The trampolines are
+     named __restore and __restore_rt.  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 (i386_linux_sigtramp_start (pc) != 0
+           || i386_linux_rt_sigtramp_start (pc) != 0);
+
+  return (strcmp ("__restore", name) == 0
+         || strcmp ("__restore_rt", name) == 0);
 }
 
-/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
-   address of the associated sigcontext structure.  */
+/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
+#define I386_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 20
 
-CORE_ADDR
-i386_linux_sigcontext_addr (struct frame_info *frame)
+/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
+   routine, return the address of the associated sigcontext structure.  */
+
+static CORE_ADDR
+i386_linux_sigcontext_addr (struct frame_info *next_frame)
 {
   CORE_ADDR pc;
+  CORE_ADDR sp;
+  char buf[4];
 
-  pc = i386_linux_sigtramp_start (frame->pc);
+  frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+  sp = extract_unsigned_integer (buf, 4);
+
+  pc = i386_linux_sigtramp_start (frame_pc_unwind (next_frame));
   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)
+      /* The sigcontext structure lives on the stack, right after
+        the signum argument.  We determine the address of the
+        sigcontext structure by looking at the frame's stack
+        pointer.  Keep in mind that the first instruction of the
+        sigtramp code is "pop %eax".  If the PC is after this
+        instruction, adjust the returned value accordingly.  */
+      if (pc == frame_pc_unwind (next_frame))
        return sp + 4;
       return sp;
     }
 
-  pc = i386_linux_rt_sigtramp_start (frame->pc);
+  pc = i386_linux_rt_sigtramp_start (frame_pc_unwind (next_frame));
   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;
+      CORE_ADDR ucontext_addr;
+
+      /* 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.  */
+      read_memory (sp + 8, buf, 4);
+      ucontext_addr = extract_unsigned_integer (buf, 4) + 20;
+      return ucontext_addr + I386_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
     }
 
   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 GNU/Linux sigtramp routine, return the
-   saved program counter.  */
-
-static 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 GNU/Linux sigtramp routine, return the
-   saved stack pointer.  */
-
-static 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);
-}
-
-/* Signal trampolines don't have a meaningful frame.  As in
-   "i386/tm-i386.h", the frame pointer value we use is actually the
-   frame pointer of the calling frame -- that is, the frame which was
-   in progress when the signal trampoline was entered.  GDB mostly
-   treats this frame pointer value as a magic cookie.  We detect the
-   case of a signal trampoline by looking at the SIGNAL_HANDLER_CALLER
-   field, which is set based on PC_IN_SIGTRAMP.
-
-   When a signal trampoline is invoked from a frameless function, we
-   essentially have two frameless functions in a row.  In this case,
-   we use the same magic cookie for three frames in a row.  We detect
-   this case by seeing whether the next frame has
-   SIGNAL_HANDLER_CALLER set, and, if it does, checking whether the
-   current frame is actually frameless.  In this case, we need to get
-   the PC by looking at the SP register value stored in the signal
-   context.
-
-   This should work in most cases except in horrible situations where
-   a signal occurs just as we enter a function but before the frame
-   has been set up.  */
-
-#define FRAMELESS_SIGNAL(frame)                                        \
-  ((frame)->next != NULL                                       \
-   && (frame)->next->signal_handler_caller                     \
-   && frameless_look_for_prologue (frame))
-
-CORE_ADDR
-i386_linux_frame_chain (struct frame_info *frame)
-{
-  if (frame->signal_handler_caller || FRAMELESS_SIGNAL (frame))
-    return frame->frame;
-
-  if (! inside_entry_file (frame->pc))
-    return read_memory_unsigned_integer (frame->frame, 4);
-
-  return 0;
-}
-
-/* Return the saved program counter for FRAME.  */
-
-CORE_ADDR
-i386_linux_frame_saved_pc (struct frame_info *frame)
-{
-  if (frame->signal_handler_caller)
-    return i386_linux_sigtramp_saved_pc (frame);
-
-  if (FRAMELESS_SIGNAL (frame))
-    {
-      CORE_ADDR sp = i386_linux_sigtramp_saved_sp (frame->next);
-      return read_memory_unsigned_integer (sp, 4);
-    }
-
-  return read_memory_unsigned_integer (frame->frame + 4, 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_unsigned_integer (read_register (SP_REGNUM), 4);
-}
-
 /* Set the program counter for process PTID to PC.  */
 
-void
+static void
 i386_linux_write_pc (CORE_ADDR pc, ptid_t ptid)
 {
-  write_register_pid (PC_REGNUM, pc, ptid);
+  write_register_pid (I386_EIP_REGNUM, pc, ptid);
 
   /* We must be careful with modifying the program counter.  If we
      just interrupted a system call, the kernel might try to restart
@@ -410,7 +319,7 @@ i386_linux_write_pc (CORE_ADDR pc, ptid_t ptid)
    be considered too special-purpose for general consumption.  */
 
 static struct minimal_symbol *
-find_minsym_and_objfile (char *name, struct objfile **objfile_p)
+find_minsym_and_objfile (char *name, struct objfile **objfilep)
 {
   struct objfile *objfile;
 
@@ -420,10 +329,10 @@ find_minsym_and_objfile (char *name, struct objfile **objfile_p)
 
       ALL_OBJFILE_MSYMBOLS (objfile, msym)
        {
-         if (SYMBOL_NAME (msym)
-             && STREQ (SYMBOL_NAME (msym), name))
+         if (SYMBOL_LINKAGE_NAME (msym)
+             && strcmp (SYMBOL_LINKAGE_NAME (msym), name) == 0)
            {
-             *objfile_p = objfile;
+             *objfilep = objfile;
              return msym;
            }
        }
@@ -433,9 +342,9 @@ find_minsym_and_objfile (char *name, struct objfile **objfile_p)
 }
 
 static CORE_ADDR
-skip_hurd_resolver (CORE_ADDR pc)
+skip_gnu_resolver (CORE_ADDR pc)
 {
-  /* The HURD dynamic linker is part of the GNU C library, so many
+  /* The GNU dynamic linker is part of the GNU C library, so many
      GNU/Linux distributions use it.  (All ELF versions, as far as I
      know.)  An unresolved PLT entry points to "_dl_runtime_resolve",
      which calls "fixup" to patch the PLT, and then passes control to
@@ -462,7 +371,7 @@ skip_hurd_resolver (CORE_ADDR pc)
        = lookup_minimal_symbol ("fixup", NULL, objfile);
 
       if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
-       return (SAVED_PC_AFTER_CALL (get_current_frame ()));
+       return frame_pc_unwind (get_current_frame ()); 
     }
 
   return 0;
@@ -481,7 +390,7 @@ i386_linux_skip_solib_resolver (CORE_ADDR pc)
   CORE_ADDR result;
 
   /* Plug in functions for other kinds of resolvers here.  */
-  result = skip_hurd_resolver (pc);
+  result = skip_gnu_resolver (pc);
   if (result)
     return result;
 
@@ -496,7 +405,7 @@ i386_linux_skip_solib_resolver (CORE_ADDR pc)
    from a GDB that was not built on an GNU/Linux x86 host (for cross
    debugging).  */
 
-struct link_map_offsets *
+static struct link_map_offsets *
 i386_linux_svr4_fetch_link_map_offsets (void)
 {
   static struct link_map_offsets lmo;
@@ -528,3 +437,71 @@ i386_linux_svr4_fetch_link_map_offsets (void)
 
   return lmp;
 }
+\f
+
+/* From <asm/sigcontext.h>.  */
+static int i386_linux_sc_reg_offset[I386_NUM_GREGS] =
+{
+  11 * 4,                      /* %eax */
+  10 * 4,                      /* %ecx */
+  9 * 4,                       /* %edx */
+  8 * 4,                       /* %ebx */
+  7 * 4,                       /* %esp */
+  6 * 4,                       /* %ebp */
+  5 * 4,                       /* %esi */
+  4 * 4,                       /* %edi */
+  14 * 4,                      /* %eip */
+  16 * 4,                      /* %eflags */
+  15 * 4,                      /* %cs */
+  18 * 4,                      /* %ss */
+  3 * 4,                       /* %ds */
+  2 * 4,                       /* %es */
+  1 * 4,                       /* %fs */
+  0 * 4                                /* %gs */
+};
+
+static void
+i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* GNU/Linux uses ELF.  */
+  i386_elf_init_abi (info, gdbarch);
+
+  /* We support the SSE registers on GNU/Linux.  */
+  tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+  /* set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS); */
+
+  /* Since we have the extra "orig_eax" register on GNU/Linux, we have
+     to adjust a few things.  */
+
+  set_gdbarch_write_pc (gdbarch, i386_linux_write_pc);
+  set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS + 1);
+  set_gdbarch_register_name (gdbarch, i386_linux_register_name);
+  set_gdbarch_register_reggroup_p (gdbarch, i386_linux_register_reggroup_p);
+
+  tdep->jb_pc_offset = 20;     /* From <bits/setjmp.h>.  */
+
+  tdep->sigcontext_addr = i386_linux_sigcontext_addr;
+  tdep->sc_reg_offset = i386_linux_sc_reg_offset;
+  tdep->sc_num_regs = I386_NUM_GREGS;
+
+  /* When the i386 Linux kernel calls a signal handler, the return
+     address points to a bit of code on the stack.  This function is
+     used to identify this bit of code as a signal trampoline in order
+     to support backtracing through calls to signal handlers.  */
+  set_gdbarch_pc_in_sigtramp (gdbarch, i386_linux_pc_in_sigtramp);
+
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+                                      i386_linux_svr4_fetch_link_map_offsets);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern void _initialize_i386_linux_tdep (void);
+
+void
+_initialize_i386_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX,
+                         i386_linux_init_abi);
+}
This page took 0.052882 seconds and 4 git commands to generate.