* valops.c (value_assign): Respect parent offset when
[deliverable/binutils-gdb.git] / gdb / i386-linux-tdep.c
index e4c56f995d879e69986ebfdf944039347f5b66f5..354daf3a48d16362f7f0427c8fedd57e4b1038e5 100644 (file)
 #include "symtab.h"
 #include "arch-utils.h"
 #include "regset.h"
+#include "xml-syscall.h"
+
+/* The syscall's XML filename for i386.  */
+#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml"
 
 #include "record.h"
 #include "linux-record.h"
@@ -290,12 +294,14 @@ i386_linux_dwarf_signal_frame_p (struct gdbarch *gdbarch,
 static CORE_ADDR
 i386_linux_sigcontext_addr (struct frame_info *this_frame)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR pc;
   CORE_ADDR sp;
   gdb_byte buf[4];
 
   get_frame_register (this_frame, I386_ESP_REGNUM, buf);
-  sp = extract_unsigned_integer (buf, 4);
+  sp = extract_unsigned_integer (buf, 4, byte_order);
 
   pc = i386_linux_sigtramp_start (this_frame);
   if (pc)
@@ -320,7 +326,7 @@ i386_linux_sigcontext_addr (struct frame_info *this_frame)
         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);
+      ucontext_addr = extract_unsigned_integer (buf, 4, byte_order);
       return ucontext_addr + I386_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
     }
 
@@ -352,6 +358,49 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
   regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1);
 }
 
+/* Record all registers but IP register for process-record.  */
+
+static int
+i386_all_but_ip_registers_record (struct regcache *regcache)
+{
+  if (record_arch_list_add_reg (regcache, I386_EAX_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_ECX_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_EDX_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_EBX_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_ESP_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_EBP_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_ESI_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_EDI_REGNUM))
+    return -1;
+  if (record_arch_list_add_reg (regcache, I386_EFLAGS_REGNUM))
+    return -1;
+
+  return 0;
+}
+
+/* i386_canonicalize_syscall maps from the native i386 Linux set
+   of syscall ids into a canonical set of syscall ids used by
+   process record (a mostly trivial mapping, since the canonical
+   set was originally taken from the i386 set).  */
+
+static enum gdb_syscall
+i386_canonicalize_syscall (int syscall)
+{
+  enum { i386_syscall_max = 499 };
+
+  if (syscall <= i386_syscall_max)
+    return syscall;
+  else
+    return -1;
+}
+
 /* Parse the arguments of current system call instruction and record
    the values of the registers and memory that will be changed into
    "record_arch_list".  This instruction is "int 0x80" (Linux
@@ -365,11 +414,30 @@ static int
 i386_linux_intx80_sysenter_record (struct regcache *regcache)
 {
   int ret;
-  uint32_t tmpu32;
+  LONGEST syscall_native;
+  enum gdb_syscall syscall_gdb;
+
+  regcache_raw_read_signed (regcache, I386_EAX_REGNUM, &syscall_native);
 
-  regcache_raw_read (regcache, I386_EAX_REGNUM, (gdb_byte *)&tmpu32);
+  syscall_gdb = i386_canonicalize_syscall (syscall_native);
 
-  ret = record_linux_system_call (tmpu32, regcache,
+  if (syscall_gdb < 0)
+    {
+      printf_unfiltered (_("Process record and replay target doesn't "
+                           "support syscall number %s\n"), 
+                        plongest (syscall_native));
+      return -1;
+    }
+
+  if (syscall_gdb == gdb_sys_sigreturn
+      || syscall_gdb == gdb_sys_rt_sigreturn)
+   {
+     if (i386_all_but_ip_registers_record (regcache))
+       return -1;
+     return 0;
+   }
+
+  ret = record_linux_system_call (syscall_gdb, regcache,
                                  &i386_linux_record_tdep);
   if (ret)
     return ret;
@@ -380,8 +448,63 @@ i386_linux_intx80_sysenter_record (struct regcache *regcache)
 
   return 0;
 }
+
+#define I386_LINUX_xstate      270
+#define I386_LINUX_frame_size  732
+
+int
+i386_linux_record_signal (struct gdbarch *gdbarch,
+                          struct regcache *regcache,
+                          enum target_signal signal)
+{
+  ULONGEST esp;
+
+  if (i386_all_but_ip_registers_record (regcache))
+    return -1;
+
+  if (record_arch_list_add_reg (regcache, I386_EIP_REGNUM))
+    return -1;
+
+  /* Record the change in the stack.  */
+  regcache_raw_read_unsigned (regcache, I386_ESP_REGNUM, &esp);
+  /* This is for xstate.
+     sp -= sizeof (struct _fpstate);  */
+  esp -= I386_LINUX_xstate;
+  /* This is for frame_size.
+     sp -= sizeof (struct rt_sigframe);  */
+  esp -= I386_LINUX_frame_size;
+  if (record_arch_list_add_mem (esp,
+                                I386_LINUX_xstate + I386_LINUX_frame_size))
+    return -1;
+
+  if (record_arch_list_add_end ())
+    return -1;
+
+  return 0;
+}
 \f
 
+static LONGEST
+i386_linux_get_syscall_number (struct gdbarch *gdbarch,
+                               ptid_t ptid)
+{
+  struct regcache *regcache = get_thread_regcache (ptid);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  /* The content of a register.  */
+  gdb_byte buf[4];
+  /* The result.  */
+  LONGEST ret;
+
+  /* Getting the system call number from the register.
+     When dealing with x86 architecture, this information
+     is stored at %eax register.  */
+  regcache_cooked_read (regcache, I386_LINUX_ORIG_EAX_REGNUM, buf);
+
+  ret = extract_signed_integer (buf, 4, byte_order);
+
+  return ret;
+}
+
 /* The register sets used in GNU/Linux ELF core-dumps are identical to
    the register sets in `struct user' that are used for a.out
    core-dumps.  These are also used by ptrace(2).  The corresponding
@@ -475,10 +598,13 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->sc_num_regs = ARRAY_SIZE (i386_linux_sc_reg_offset);
 
   set_gdbarch_process_record (gdbarch, i386_process_record);
+  set_gdbarch_process_record_signal (gdbarch, i386_linux_record_signal);
 
   /* Initialize the i386_linux_record_tdep.  */
   /* These values are the size of the type that will be used in a system
      call.  They are obtained from Linux Kernel source.  */
+  i386_linux_record_tdep.size_pointer
+    = gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT;
   i386_linux_record_tdep.size__old_kernel_stat = 32;
   i386_linux_record_tdep.size_tms = 16;
   i386_linux_record_tdep.size_loff_t = 8;
@@ -499,9 +625,12 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   i386_linux_record_tdep.size_statfs = 64;
   i386_linux_record_tdep.size_statfs64 = 84;
   i386_linux_record_tdep.size_sockaddr = 16;
-  i386_linux_record_tdep.size_int = 4;
-  i386_linux_record_tdep.size_long = 4;
-  i386_linux_record_tdep.size_ulong = 4;
+  i386_linux_record_tdep.size_int
+    = gdbarch_int_bit (gdbarch) / TARGET_CHAR_BIT;
+  i386_linux_record_tdep.size_long
+    = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT;
+  i386_linux_record_tdep.size_ulong
+    = gdbarch_long_bit (gdbarch) / TARGET_CHAR_BIT;
   i386_linux_record_tdep.size_msghdr = 28;
   i386_linux_record_tdep.size_itimerval = 16;
   i386_linux_record_tdep.size_stat = 88;
@@ -534,7 +663,8 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   i386_linux_record_tdep.size_io_event = 32;
   i386_linux_record_tdep.size_iocb = 64;
   i386_linux_record_tdep.size_epoll_event = 12;
-  i386_linux_record_tdep.size_itimerspec = i386_linux_record_tdep.size_timespec * 2;
+  i386_linux_record_tdep.size_itimerspec
+    = i386_linux_record_tdep.size_timespec * 2;
   i386_linux_record_tdep.size_mq_attr = 32;
   i386_linux_record_tdep.size_siginfo = 128;
   i386_linux_record_tdep.size_termios = 36;
@@ -544,6 +674,8 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   i386_linux_record_tdep.size_serial_struct = 60;
   i386_linux_record_tdep.size_serial_icounter_struct = 80;
   i386_linux_record_tdep.size_hayes_esp_config = 12;
+  i386_linux_record_tdep.size_size_t = 4;
+  i386_linux_record_tdep.size_iovec = 8;
 
   /* These values are the second argument of system call "sys_ioctl".
      They are obtained from Linux Kernel source.  */
@@ -625,6 +757,7 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   i386_linux_record_tdep.arg3 = I386_EDX_REGNUM;
   i386_linux_record_tdep.arg4 = I386_ESI_REGNUM;
   i386_linux_record_tdep.arg5 = I386_EDI_REGNUM;
+  i386_linux_record_tdep.arg6 = I386_EBP_REGNUM;
 
   tdep->i386_intx80_record = i386_linux_intx80_sysenter_record;
   tdep->i386_sysenter_record = i386_linux_intx80_sysenter_record;
@@ -659,6 +792,11 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_gdbarch_displaced_step_location (gdbarch,
                                        displaced_step_at_entry_point);
 
+  /* Functions for 'catch syscall'.  */
+  set_xml_syscall_file_name (XML_SYSCALL_FILENAME_I386);
+  set_gdbarch_get_syscall_number (gdbarch,
+                                  i386_linux_get_syscall_number);
+
   set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
 }
 
This page took 0.025952 seconds and 4 git commands to generate.