Add a symbol's value to the computed frag offset, rather than overwriting it.
[deliverable/binutils-gdb.git] / gdb / i386-tdep.c
index 3e50ca89edc73f51133896344843cf3fe5a3b15a..1fbf76ab966e9925f6375ecec68c975a734587d5 100644 (file)
@@ -46,6 +46,32 @@ static int gdb_print_insn_i386 (bfd_vma, disassemble_info *);
 
 void _initialize_i386_tdep PARAMS ((void));
 
+/* i386_register_byte[i] is the offset into the register file of the
+   start of register number i.  We initialize this from
+   i386_register_raw_size.  */
+int i386_register_byte[MAX_NUM_REGS];
+
+/* i386_register_raw_size[i] is the number of bytes of storage in the
+   actual machine representation for register i.  */
+int i386_register_raw_size[MAX_NUM_REGS] = {
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+  10, 10, 10, 10,
+  10, 10, 10, 10,
+   4,  4,  4,  4,
+   4,  4,  4,  4,
+  16, 16, 16, 16,
+  16, 16, 16, 16,
+   4
+};
+
+/* i386_register_virtual_size[i] is the size in bytes of the virtual
+   type of register i.  */
+int i386_register_virtual_size[MAX_NUM_REGS];
+
+
 /* This is the variable the is set with "set disassembly-flavor",
    and its legitimate values. */
 static char att_flavor[] = "att";
@@ -58,11 +84,11 @@ static char *valid_flavors[] =
 };
 static char *disassembly_flavor = att_flavor;
 
+static void i386_print_register PARAMS ((char *, int, int));
+
 /* This is used to keep the bfd arch_info in sync with the disassembly flavor.  */
 static void set_disassembly_flavor_sfunc PARAMS ((char *, int, struct cmd_list_element *));
-static void set_disassembly_flavor ();
-
-void (*disassembly_flavor_hook) PARAMS ((char *args, int from_tty));
+static void set_disassembly_flavor PARAMS ((void));
 
 /* Stdio style buffering was used to minimize calls to ptrace, but this
    buffering did not take into account that the code section being accessed
@@ -676,21 +702,47 @@ i386_extract_return_value (type, regbuf, valbuf)
      char regbuf[REGISTER_BYTES];
      char *valbuf;
 {
-/* On AIX, floating point values are returned in floating point registers.  */
-#ifdef I386_AIX_TARGET
+  /* On AIX and i386 GNU/Linux, floating point values are returned in
+     floating point registers.  */
+#if defined(I386_AIX_TARGET) || defined(I386_GNULINUX_TARGET)
   if (TYPE_CODE_FLT == TYPE_CODE (type))
     {
       double d;
       /* 387 %st(0), gcc uses this */
       floatformat_to_double (&floatformat_i387_ext,
+#if defined(FPDATA_REGNUM)
+                            &regbuf[REGISTER_BYTE (FPDATA_REGNUM)],
+#else /* !FPDATA_REGNUM */
                             &regbuf[REGISTER_BYTE (FP0_REGNUM)],
+#endif /* FPDATA_REGNUM */
+
                             &d);
       store_floating (valbuf, TYPE_LENGTH (type), d);
     }
   else
-#endif /* I386_AIX_TARGET */
+#endif /* I386_AIX_TARGET || I386_GNULINUX_TARGET*/
     {
+#if defined(LOW_RETURN_REGNUM)
+      int len = TYPE_LENGTH (type);
+      int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
+      int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+
+      if (len <= low_size)
+       memcpy (valbuf, regbuf + REGISTER_BYTE (LOW_RETURN_REGNUM), len);
+      else if (len <= (low_size + high_size))
+       {
+         memcpy (valbuf,
+                 regbuf + REGISTER_BYTE (LOW_RETURN_REGNUM),
+                 low_size);
+         memcpy (valbuf + low_size,
+                 regbuf + REGISTER_BYTE (HIGH_RETURN_REGNUM),
+                 len - low_size);
+       }
+      else
+       error ("GDB bug: i386-tdep.c (i386_extract_return_value): Don't know how to find a return value %d bytes long", len);
+#else /* !LOW_RETURN_REGNUM */
       memcpy (valbuf, regbuf, TYPE_LENGTH (type));
+#endif /* LOW_RETURN_REGNUM */
     }
 }
 
@@ -722,6 +774,140 @@ i386v4_sigtramp_saved_pc (frame)
 }
 #endif /* I386V4_SIGTRAMP_SAVED_PC */
 
+#ifdef I386_LINUX_SIGTRAMP
+
+/* When the i386 Linux kernel calls a signal handler, 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 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.  */
+
+#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 (pc)
+     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;
+}
+
+/* Return whether PC is in a Linux sigtramp routine.  */
+
+int
+i386_linux_sigtramp (pc)
+     CORE_ADDR pc;
+{
+  return i386_linux_sigtramp_start (pc) != 0;
+}
+
+/* Assuming FRAME is for a Linux sigtramp routine, return the saved
+   program counter.  The Linux kernel will set up a sigcontext
+   structure immediately before the sigtramp routine on the stack.  */
+
+CORE_ADDR
+i386_linux_sigtramp_saved_pc (frame)
+     struct frame_info *frame;
+{
+  CORE_ADDR pc;
+
+  pc = i386_linux_sigtramp_start (frame->pc);
+  if (pc == 0)
+    error ("i386_linux_sigtramp_saved_pc called when no sigtramp");
+  return read_memory_integer ((pc
+                              - LINUX_SIGCONTEXT_SIZE
+                              + LINUX_SIGCONTEXT_PC_OFFSET),
+                             4);
+}
+
+/* Assuming FRAME is for a Linux sigtramp routine, return the saved
+   stack pointer.  The Linux kernel will set up a sigcontext structure
+   immediately before the sigtramp routine on the stack.  */
+
+CORE_ADDR
+i386_linux_sigtramp_saved_sp (frame)
+     struct frame_info *frame;
+{
+  CORE_ADDR pc;
+
+  pc = i386_linux_sigtramp_start (frame->pc);
+  if (pc == 0)
+    error ("i386_linux_sigtramp_saved_sp called when no sigtramp");
+  return read_memory_integer ((pc
+                              - LINUX_SIGCONTEXT_SIZE
+                              + LINUX_SIGCONTEXT_SP_OFFSET),
+                             4);
+}
+
+#endif /* I386_LINUX_SIGTRAMP */
+
 #ifdef STATIC_TRANSFORM_NAME
 /* SunPRO encodes the static variables.  This is not related to C++ mangling,
    it is done for C too.  */
@@ -799,9 +985,6 @@ set_disassembly_flavor_sfunc (args, from_tty, c)
      struct cmd_list_element *c;
 {
   set_disassembly_flavor ();
-
-  if (disassembly_flavor_hook != NULL)
-    disassembly_flavor_hook (args, from_tty);
 }
 
 static void
@@ -813,28 +996,50 @@ set_disassembly_flavor ()
     set_architecture_from_arch_mach (bfd_arch_i386, bfd_mach_i386_i386_intel_syntax);
 }
 
+
 void
 _initialize_i386_tdep ()
 {
-  struct cmd_list_element *new_cmd;
+  /* Initialize the table saying where each register starts in the
+     register file.  */
+  {
+    int i, offset;
+
+    offset = 0;
+    for (i = 0; i < MAX_NUM_REGS; i++)
+      {
+       i386_register_byte[i] = offset;
+       offset += i386_register_raw_size[i];
+      }
+  }
+
+  /* Initialize the table of virtual register sizes.  */
+  {
+    int i;
+
+    for (i = 0; i < MAX_NUM_REGS; i++)
+      i386_register_virtual_size[i] = TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (i));
+  }
 
   tm_print_insn = gdb_print_insn_i386;
   tm_print_insn_info.mach = bfd_lookup_arch (bfd_arch_i386, 0)->mach;
 
   /* Add the variable that controls the disassembly flavor */
+  {
+    struct cmd_list_element *new_cmd;
 
-  new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class,
-                             valid_flavors,
-                             (char *) &disassembly_flavor,
-                             "Set the disassembly flavor, the valid values are \"att\" and \"intel\", \
+    new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class,
+                               valid_flavors,
+                               (char *) &disassembly_flavor,
+                               "Set the disassembly flavor, the valid values are \"att\" and \"intel\", \
 and the default value is \"att\".",
-                             &setlist);
-  new_cmd->function.sfunc = set_disassembly_flavor_sfunc;
-  add_show_from_set (new_cmd, &showlist);
+                               &setlist);
+    new_cmd->function.sfunc = set_disassembly_flavor_sfunc;
+    add_show_from_set (new_cmd, &showlist);
+  }
 
   /* Finally, initialize the disassembly flavor to the default given
      in the disassembly_flavor variable */
 
   set_disassembly_flavor ();
-
 }
This page took 0.026623 seconds and 4 git commands to generate.