This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GDB record patch 0.1.6 for GDB branch msnyder-reverse-20080609-branch release


GDB record patch make GDB support Reversible Debugging.
It make GDB disassemble the instruction that will be executed to get
which memory and register will be changed and record them to record
all program running message. Through these on the use of this
information to achieve the implementation of the GDB Reversible
Debugging function.
To get more message, you can go to http://sourceforge.net/projects/record/ .

The main change of this version is change record function to be a
target of GDB. Then it can work with the interface of branch
msnyder-reverse-20080609-branch. The command in this branch is so cool
such as "rn"(reverse-next), "rs"(reverse-step) and
"rc"(reverse-continue). I like it. :)
You can start record target with command "rec"(record) or "target record".
I try to use some simple commands such as "disconnect" and "detach" to
instead command "delrecord"(dr) and "stoprecord"(sr). But these
commands all have other affect to GDB such as call function
"no_shared_libraries". So I keep the command "delrecord"(dr) and
"stoprecord"(sr).

Please give me your advice about GDB record. Thanks a lot. :)

teawater
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 891b31a..f6a36b8 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -641,7 +641,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c  \
 	user-regs.c \
 	valarith.c valops.c valprint.c value.c varobj.c vec.c \
 	wrapper.c \
-	xml-tdesc.c xml-support.c
+	xml-tdesc.c xml-support.c \
+	record.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -920,6 +921,7 @@ xcoffsolib_h = xcoffsolib.h
 xml_support_h = xml-support.h $(gdb_obstack_h) $(vec_h)
 xml_tdesc_h = xml-tdesc.h
 xtensa_tdep_h = xtensa-tdep.h 
+record_h = record.h
 
 #
 # gdb/cli/ headers
@@ -1091,7 +1093,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	tramp-frame.o \
 	solib.o solib-null.o \
 	prologue-value.o memory-map.o xml-support.o \
-	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o
+	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
+	record.o
 
 TSOBS = inflow.o
 
@@ -2269,7 +2272,7 @@ i386-linux-tdep.o: i386-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \
 	$(value_h) $(regcache_h) $(inferior_h) $(osabi_h) $(reggroups_h) \
 	$(dwarf2_frame_h) $(gdb_string_h) $(i386_tdep_h) \
 	$(i386_linux_tdep_h) $(glibc_tdep_h) $(solib_svr4_h) $(symtab_h) \
-	$(arch_utils_h) $(regset_h)
+	$(arch_utils_h) $(regset_h) $(record_h)
 i386-nat.o: i386-nat.c $(defs_h) $(breakpoint_h) $(command_h) $(gdbcmd_h) \
 	$(target_h)
 i386nbsd-nat.o: i386nbsd-nat.c $(defs_h) $(gdbcore_h) $(regcache_h) \
@@ -2301,7 +2304,7 @@ i386-tdep.o: i386-tdep.c $(defs_h) $(arch_utils_h) $(command_h) \
 	$(gdbcmd_h) $(gdbcore_h) $(objfiles_h) $(osabi_h) $(regcache_h) \
 	$(reggroups_h) $(regset_h) $(symfile_h) $(symtab_h) $(target_h) \
 	$(value_h) $(dis_asm_h) $(gdb_assert_h) $(gdb_string_h) \
-	$(i386_tdep_h) $(i387_tdep_h)
+	$(i386_tdep_h) $(i387_tdep_h) $(record_h)
 i386v4-nat.o: i386v4-nat.c $(defs_h) $(value_h) $(inferior_h) $(regcache_h) \
 	$(i386_tdep_h) $(i387_tdep_h) $(gregset_h)
 i387-tdep.o: i387-tdep.c $(defs_h) $(doublest_h) $(floatformat_h) $(frame_h) \
@@ -2332,13 +2335,14 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \
 	$(objfiles_h) $(completer_h) $(ui_out_h) $(event_top_h) \
 	$(parser_defs_h) $(regcache_h) $(reggroups_h) $(block_h) \
 	$(solib_h) $(gdb_assert_h) $(observer_h) $(target_descriptions_h) \
-	$(user_regs_h) $(exceptions_h) $(cli_decode_h) $(gdbthread_h)
+	$(user_regs_h) $(exceptions_h) $(cli_decode_h) $(gdbthread_h) \
+	$(record_h)
 inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \
 	$(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h) \
 	$(language_h)
 inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
 	$(serial_h) $(terminal_h) $(target_h) $(gdbthread_h) $(gdb_string_h) \
-	$(inflow_h) $(gdb_select_h)
+	$(inflow_h) $(gdb_select_h) $(record_h)
 inf-ptrace.o: inf-ptrace.c $(defs_h) $(command_h) $(inferior_h) $(inflow_h) \
 	$(gdbcore_h) $(regcache_h) $(gdb_stdint_h) $(gdb_assert_h) \
 	$(gdb_string_h) $(gdb_ptrace_h) $(gdb_wait_h) $(inf_child_h)
@@ -2347,7 +2351,7 @@ infrun.o: infrun.c $(defs_h) $(gdb_string_h) $(symtab_h) $(frame_h) \
 	$(gdbcore_h) $(gdbcmd_h) $(cli_script_h) $(target_h) $(gdbthread_h) \
 	$(annotate_h) $(symfile_h) $(top_h) $(inf_loop_h) $(regcache_h) \
 	$(value_h) $(observer_h) $(language_h) $(solib_h) $(gdb_assert_h) \
-	$(mi_common_h) $(main_h)
+	$(mi_common_h) $(main_h) $(record_h)
 inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(gdbcore_h) \
 	$(gdbthread_h) $(inferior_h) $(target_h) \
 	$(gdb_assert_h) $(gdb_string_h) $(inf_child_h) $(inf_ttrace_h)
@@ -2393,7 +2397,8 @@ linux-nat.o: linux-nat.c $(defs_h) $(inferior_h) $(target_h) $(gdb_string_h) \
 	$(gdb_wait_h) $(gdb_assert_h) $(linux_nat_h) $(gdbthread_h) \
 	$(gdbcmd_h) $(regcache_h) $(regset_h) $(inf_ptrace_h) $(auxv_h) \
 	$(elf_bfd_h) $(gregset_h) $(gdbcore_h) $(gdbthread_h) $(gdb_stat_h) \
-	$(linux_fork_h) $(inf_loop_h) $(event_loop_h) $(event_top_h)
+	$(linux_fork_h) $(inf_loop_h) $(event_loop_h) $(event_top_h) \
+	$(record_h)
 linux-thread-db.o: linux-thread-db.c $(defs_h) $(gdb_assert_h) \
 	$(gdb_proc_service_h) $(gdb_thread_db_h) $(bfd_h) $(exceptions_h) \
 	$(gdbthread_h) $(inferior_h) $(symfile_h) $(objfiles_h) $(target_h) \
@@ -2661,7 +2666,7 @@ p-valprint.o: p-valprint.c $(defs_h) $(gdb_obstack_h) $(symtab_h) \
 	$(cp_support_h)
 regcache.o: regcache.c $(defs_h) $(inferior_h) $(target_h) $(gdbarch_h) \
 	$(gdbcmd_h) $(regcache_h) $(reggroups_h) $(gdb_assert_h) \
-	$(gdb_string_h) $(gdbcmd_h) $(observer_h)
+	$(gdb_string_h) $(gdbcmd_h) $(observer_h) $(record_h)
 reggroups.o: reggroups.c $(defs_h) $(reggroups_h) $(gdbtypes_h) \
 	$(gdb_assert_h) $(regcache_h) $(command_h) $(gdbcmd_h)
 regset.o: regset.c $(defs_h) $(regset_h) $(gdb_assert_h)
@@ -3047,6 +3052,8 @@ xtensa-tdep.o: xtensa-tdep.c $(defs_h) $(doublest_h) $(frame_h) \
 	$(reggroups_h) $(arch_utils_h) $(osabi_h) $(block_h) $(gdb_assert_h) \
 	$(elf_bfd_h) $(xtensa_tdep_h) $(dwarf2_frame_h) $(solib_svr4_h)
 xtensa-config.o: $(defs_h) $(xtensa_tdep_h)
+record.o: record.c $(defs_h) $(target_h) $(gdbcmd_h) $(regcache_h) \
+	$(inferior_h) $(record_h)
 
 #
 # gdb/cli/ dependencies
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 6594b35..deeb04f 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -238,6 +238,8 @@ struct gdbarch
   gdbarch_target_signal_from_host_ftype *target_signal_from_host;
   gdbarch_target_signal_to_host_ftype *target_signal_to_host;
   gdbarch_record_special_symbol_ftype *record_special_symbol;
+  gdbarch_record_ftype *record;
+  gdbarch_record_dasm_ftype *record_dasm;
 };
 
 
@@ -368,6 +370,8 @@ struct gdbarch startup_gdbarch =
   default_target_signal_from_host,  /* target_signal_from_host */
   default_target_signal_to_host,  /* target_signal_to_host */
   0,  /* record_special_symbol */
+  NULL,  /* record_ftype */
+  NULL,  /* record_dasm_ftype */
   /* startup_gdbarch() */
 };
 
@@ -3621,6 +3625,46 @@ deprecated_current_gdbarch_select_hack (struct gdbarch *new_gdbarch)
   reinit_frame_cache ();
 }
 
+int
+gdbarch_record_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return (gdbarch->record != NULL);
+}
+
+int
+gdbarch_record (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->record != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_record called\n");
+  return (gdbarch->record (gdbarch, addr));
+}
+
+void
+set_gdbarch_record (struct gdbarch *gdbarch, gdbarch_record_ftype * record)
+{
+  gdbarch->record = record;
+}
+
+void
+gdbarch_record_dasm (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->record_dasm != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_record_dasm called\n");
+  gdbarch->record_dasm (gdbarch);
+}
+
+void
+set_gdbarch_record_dasm (struct gdbarch *gdbarch,
+			 gdbarch_record_dasm_ftype * record_dasm)
+{
+  gdbarch->record_dasm = record_dasm;
+}
+
 extern void _initialize_gdbarch (void);
 
 void
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 44d1f2d..fa08227 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -975,6 +975,20 @@ extern struct gdbarch *gdbarch_find_by_info (struct gdbarch_info info);
 extern void deprecated_current_gdbarch_select_hack (struct gdbarch *gdbarch);
 
 
+/* For the record target */
+
+extern int gdbarch_record_p (struct gdbarch *gdbarch);
+typedef int (gdbarch_record_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern int gdbarch_record (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_record (struct gdbarch *gdbarch,
+				gdbarch_record_ftype * record);
+
+typedef void (gdbarch_record_dasm_ftype) (struct gdbarch *gdbarch);
+extern void gdbarch_record_dasm (struct gdbarch *gdbarch);
+extern void set_gdbarch_record_dasm (struct gdbarch *gdbarch,
+				     gdbarch_record_dasm_ftype * record_dasm);
+
+
 /* Register per-architecture data-pointer.
 
    Reserve space for a per-architecture data-pointer.  An identifier
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index 5284f4a..0d3d205 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -37,6 +37,9 @@
 #include "arch-utils.h"
 #include "regset.h"
 
+#include "record.h"
+#include <stdint.h>
+
 /* Supported register note sections.  */
 static struct core_regset_section i386_linux_regset_sections[] =
 {
@@ -347,6 +350,2530 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
   regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1);
 }
 
+/* These macros are the size of the type that will be use in system call. The values of
+   these macros are gotten from Linux Kernel source. */
+#define I386_RECORD_SIZE__old_kernel_stat	32
+#define I386_RECORD_SIZE_tms			16
+#define I386_RECORD_SIZE_loff_t			8
+#define I386_RECORD_SIZE_flock			16
+#define I386_RECORD_SIZE_oldold_utsname		45
+#define I386_RECORD_SIZE_ustat			20
+#define I386_RECORD_SIZE_old_sigaction		140
+#define I386_RECORD_SIZE_old_sigset_t		128
+#define I386_RECORD_SIZE_rlimit			8
+#define I386_RECORD_SIZE_rusage			72
+#define I386_RECORD_SIZE_timeval		8
+#define I386_RECORD_SIZE_timezone		8
+#define I386_RECORD_SIZE_old_gid_t		2
+#define I386_RECORD_SIZE_old_uid_t		2
+#define I386_RECORD_SIZE_fd_set			128
+#define I386_RECORD_SIZE_dirent			268
+#define I386_RECORD_SIZE_dirent64		276
+#define I386_RECORD_SIZE_statfs			64
+#define I386_RECORD_SIZE_statfs64		84
+#define I386_RECORD_SIZE_sockaddr		16
+#define I386_RECORD_SIZE_int			4
+#define I386_RECORD_SIZE_long			4
+#define I386_RECORD_SIZE_ulong			4
+#define I386_RECORD_SIZE_msghdr			28
+#define I386_RECORD_SIZE_itimerval		16
+#define I386_RECORD_SIZE_stat			88
+#define I386_RECORD_SIZE_old_utsname		325
+#define I386_RECORD_SIZE_rusage			72
+#define I386_RECORD_SIZE_sysinfo		64
+#define I386_RECORD_SIZE_msqid_ds		88
+#define I386_RECORD_SIZE_shmid_ds		84
+#define I386_RECORD_SIZE_new_utsname		390
+#define I386_RECORD_SIZE_timex			128
+#define I386_RECORD_SIZE_mem_dqinfo		24
+#define I386_RECORD_SIZE_if_dqblk		68
+#define I386_RECORD_SIZE_fs_quota_stat		68
+#define I386_RECORD_SIZE_timespec		8
+#define I386_RECORD_SIZE_pollfd			8
+#define I386_RECORD_SIZE_NFS_FHSIZE		32
+#define I386_RECORD_SIZE_knfsd_fh		132
+#define I386_RECORD_SIZE_TASK_COMM_LEN		16
+#define I386_RECORD_SIZE_sigaction		140
+#define I386_RECORD_SIZE_sigset_t		8
+#define I386_RECORD_SIZE_siginfo_t		128
+#define I386_RECORD_SIZE_cap_user_data_t	12
+#define I386_RECORD_SIZE_stack_t		12
+#define I386_RECORD_SIZE_off_t			I386_RECORD_SIZE_long
+#define I386_RECORD_SIZE_stat64			96
+#define I386_RECORD_SIZE_gid_t			2
+#define I386_RECORD_SIZE_uid_t			2
+#define I386_RECORD_SIZE_uid_t			2
+#define I386_RECORD_SIZE_PAGE_SIZE		4096
+#define I386_RECORD_SIZE_flock64		24
+#define I386_RECORD_SIZE_user_desc		16
+#define I386_RECORD_SIZE_io_event		32
+#define I386_RECORD_SIZE_iocb			64
+#define I386_RECORD_SIZE_epoll_event		12
+#define I386_RECORD_SIZE_itimerspec		(I386_RECORD_SIZE_timespec * 2)
+#define I386_RECORD_SIZE_mq_attr		32
+#define I386_RECORD_SIZE_siginfo		128
+#define I386_RECORD_SIZE_rusage			72
+
+/* These macros are the values of the first argument of system call
+   "sys_ptrace". The values of these macros are gotten from Linux Kernel
+   source. */
+#define I386_RECORD_PTRACE_PEEKTEXT	1
+#define I386_RECORD_PTRACE_PEEKDATA	2
+#define I386_RECORD_PTRACE_PEEKUSR	3
+
+/* These macros are the values of the second argument of system call
+   "sys_ioctl". The values of these macros are gotten from Linux Kernel
+   source. */
+#define I386_RECORD_FIONCLEX	0x5450
+#define I386_RECORD_FIOCLEX	0x5451
+#define I386_RECORD_FIONBIO	0x5421
+#define I386_RECORD_FIOASYNC	0x5452
+#define I386_RECORD_FIOQSIZE	0x5460
+
+/* These macros are the values of the first argument of system call
+   "sys_socketcall". The values of these macros are gotten from Linux Kernel
+   source. */
+#define I386_RECORD_SYS_SOCKET		1
+#define I386_RECORD_SYS_BIND		2
+#define I386_RECORD_SYS_CONNECT	3
+#define I386_RECORD_SYS_LISTEN		4
+#define I386_RECORD_SYS_ACCEPT		5
+#define I386_RECORD_SYS_GETSOCKNAME	6
+#define I386_RECORD_SYS_GETPEERNAME	7
+#define I386_RECORD_SYS_SOCKETPAIR	8
+#define I386_RECORD_SYS_SEND		9
+#define I386_RECORD_SYS_RECV		10
+#define I386_RECORD_SYS_SENDTO		11
+#define I386_RECORD_SYS_RECVFROM	12
+#define I386_RECORD_SYS_SHUTDOWN	13
+#define I386_RECORD_SYS_SETSOCKOPT	14
+#define I386_RECORD_SYS_GETSOCKOPT	15
+#define I386_RECORD_SYS_SENDMSG	16
+#define I386_RECORD_SYS_RECVMSG	17
+
+/* These macros are the values of the first argument of system call
+   "sys_ipc". The values of these macros are gotten from Linux Kernel source. */
+#define I386_RECORD_SEMOP		1
+#define I386_RECORD_SEMGET		2
+#define I386_RECORD_SEMCTL		3
+#define I386_RECORD_SEMTIMEDOP		4
+#define I386_RECORD_MSGSND		11
+#define I386_RECORD_MSGRCV		12
+#define I386_RECORD_MSGGET		13
+#define I386_RECORD_MSGCTL		14
+#define I386_RECORD_SHMAT		21
+#define I386_RECORD_SHMDT		22
+#define I386_RECORD_SHMGET		23
+#define I386_RECORD_SHMCTL		24
+
+/* These macros are the values of the first argument of system call
+   "sys_quotactl". The values of these macros are gotten from Linux Kernel
+   source. */
+#define I386_RECORD_Q_GETFMT		0x800004
+#define I386_RECORD_Q_GETINFO		0x800005
+#define I386_RECORD_Q_GETQUOTA		0x800007
+#define I386_RECORD_Q_XGETQSTAT	(('5'<<8)+(5))
+#define I386_RECORD_Q_XGETQUOTA	(('3'<<8)+(3))
+
+/* Parse the arguments of current system call instruction and record the
+   values of the registers and memory that will be changed in current system
+   call instruction to "record_arch_list". This instruction is "int 0x80" (Linux
+   Kernel2.4) or "sysenter" (Linux Kernel 2.6).
+   Return -1 if something wrong. */
+static int
+i386_linux_intx80_sysenter_record (void)
+{
+  uint32_t tmpu32;
+
+  regcache_raw_read (record_regcache, I386_EAX_REGNUM, (gdb_byte *) & tmpu32);
+  switch (tmpu32)
+    {
+      /* sys_restart_syscall */
+    case 0:
+      {
+	int q;
+	target_terminal_ours ();
+	q =
+	  yquery (_
+		  ("The next instruction is syscall restart. It will restart the computer. Do you want to pause the program."));
+	target_terminal_inferior ();
+	if (q)
+	  {
+	    return (1);
+	  }
+      }
+      break;
+
+      /* sys_exit */
+    case 1:
+      {
+	int q;
+	target_terminal_ours ();
+	q =
+	  yquery (_
+		  ("The next instruction is syscall exit. It will make the program exit. Do you want to pause the program."));
+	target_terminal_inferior ();
+	if (q)
+	  {
+	    return (1);
+	  }
+      }
+      break;
+
+      /* sys_fork */
+    case 2:
+      break;
+
+      /* sys_read */
+    case 3:
+      {
+	uint32_t addr, count;
+	regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			   (gdb_byte *) & addr);
+	regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			   (gdb_byte *) & count);
+	if (record_arch_list_add_mem (addr, count))
+	  {
+	    return (-1);
+	  }
+      }
+      break;
+
+      /* sys_write */
+    case 4:
+      /* sys_open */
+    case 5:
+      /* sys_close */
+    case 6:
+      /* sys_waitpid */
+    case 7:
+      /* sys_creat */
+    case 8:
+      /* sys_link */
+    case 9:
+      /* sys_unlink */
+    case 10:
+      /* sys_execve */
+    case 11:
+      /* sys_chdir */
+    case 12:
+      /* sys_time */
+    case 13:
+      /* sys_mknod */
+    case 14:
+      /* sys_chmod */
+    case 15:
+      /* sys_lchown16 */
+    case 16:
+      /* sys_ni_syscall */
+    case 17:
+      break;
+
+      /* sys_stat */
+    case 18:
+      /* sys_fstat */
+    case 28:
+      /* sys_lstat */
+    case 84:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE__old_kernel_stat))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_lseek */
+    case 19:
+      /* sys_getpid */
+    case 20:
+      /* sys_mount */
+    case 21:
+      /* sys_oldumount */
+    case 22:
+      /* sys_setuid16 */
+    case 23:
+      /* sys_getuid16 */
+    case 24:
+      /* sys_stime */
+    case 25:
+      break;
+
+      /* sys_ptrace */
+    case 26:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32 == I386_RECORD_PTRACE_PEEKTEXT
+	  || tmpu32 == I386_RECORD_PTRACE_PEEKDATA
+	  || tmpu32 == I386_RECORD_PTRACE_PEEKUSR)
+	{
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, 4))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_alarm */
+    case 27:
+      /* sys_pause */
+    case 29:
+      /* sys_utime    */
+    case 30:
+      /* sys_ni_syscall */
+    case 31:
+      /* sys_ni_syscall */
+    case 32:
+      /* sys_access */
+    case 33:
+      /* sys_nice */
+    case 34:
+      /* sys_ni_syscall */
+    case 35:
+      /* sys_sync */
+    case 36:
+      /* sys_kill */
+    case 37:
+      /* sys_rename */
+    case 38:
+      /* sys_mkdir */
+    case 39:
+      /* sys_rmdir */
+    case 40:
+      /* sys_dup */
+    case 41:
+      /* sys_pipe */
+    case 42:
+      break;
+
+      /* sys_times */
+    case 43:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_tms))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_ni_syscall */
+    case 44:
+      /* sys_brk */
+    case 45:
+      /* sys_setgid16 */
+    case 46:
+      /* sys_getgid16 */
+    case 47:
+      /* sys_signal */
+    case 48:
+      /* sys_geteuid16 */
+    case 49:
+      /* sys_getegid16 */
+    case 50:
+      /* sys_acct */
+    case 51:
+      /* sys_umount */
+    case 52:
+      /* sys_ni_syscall */
+    case 53:
+      break;
+
+      /* sys_ioctl */
+    case 54:
+      /* XXX */
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+	{
+	case I386_RECORD_FIOCLEX:
+	case I386_RECORD_FIONCLEX:
+	case I386_RECORD_FIONBIO:
+	case I386_RECORD_FIOASYNC:
+	  break;
+	case I386_RECORD_FIOQSIZE:
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+	    {
+	      return (-1);
+	    }
+	  break;
+	default:
+	  printf_unfiltered (_
+			     ("Record: record and reverse function don't support ioctl request 0x%08x\n"),
+			     tmpu32);
+	  return (-1);
+	  break;
+	}
+      break;
+
+      /* sys_fcntl */
+    case 55:
+      /* XXX */
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+    sys_fcntl:
+      if (tmpu32 == F_GETLK)
+	{
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_flock))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_ni_syscall */
+    case 56:
+      /* sys_setpgid */
+    case 57:
+      /* sys_ni_syscall */
+    case 58:
+      break;
+
+      /* sys_olduname */
+    case 59:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_oldold_utsname))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_umask */
+    case 60:
+      /* sys_chroot */
+    case 61:
+      break;
+
+      /* sys_ustat */
+    case 62:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_ustat))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_dup2 */
+    case 63:
+      /* sys_getppid */
+    case 64:
+      /* sys_getpgrp */
+    case 65:
+      /* sys_setsid */
+    case 66:
+      break;
+
+      /* sys_sigaction */
+    case 67:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_sigaction))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_sgetmask */
+    case 68:
+      /* sys_ssetmask */
+    case 69:
+      /* sys_setreuid16 */
+    case 70:
+      /* sys_setregid16 */
+    case 71:
+      /* sys_sigsuspend */
+    case 72:
+      break;
+
+      /* sys_sigpending */
+    case 73:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_sigset_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_sethostname */
+    case 74:
+      /* sys_setrlimit */
+    case 75:
+      break;
+
+      /* sys_old_getrlimit */
+    case 76:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rlimit))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_getrusage */
+    case 77:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rusage))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_gettimeofday */
+    case 78:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timeval))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timezone))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_settimeofday */
+    case 79:
+      break;
+
+      /* sys_getgroups16 */
+    case 80:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_setgroups16 */
+    case 81:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* old_select */
+    case 82:
+      {
+	/*
+	   struct sel_arg_struct {
+	   unsigned long n;
+	   fd_set *inp;
+	   fd_set *outp;
+	   fd_set *exp;
+	   struct timeval *tvp;
+	   };
+	 */
+	struct sel_arg_struct
+	{
+	  uint32_t n;
+	  uint32_t inp;
+	  uint32_t outp;
+	  uint32_t exp;
+	  uint32_t tvp;
+	} sel;
+
+	regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			   (gdb_byte *) & tmpu32);
+	if (tmpu32)
+	  {
+	    if (target_read_memory (tmpu32, (gdb_byte *) & sel, sizeof (sel)))
+	      {
+		fprintf_unfiltered (gdb_stdlog,
+				    "Record: read memory addr = 0x%s len = %d error.\n",
+				    paddr_nz (tmpu32), sizeof (sel));
+		return (-1);
+	      }
+	    if (record_arch_list_add_mem (sel.inp, I386_RECORD_SIZE_fd_set))
+	      {
+		return (-1);
+	      }
+	    if (record_arch_list_add_mem (sel.outp, I386_RECORD_SIZE_fd_set))
+	      {
+		return (-1);
+	      }
+	    if (record_arch_list_add_mem (sel.exp, I386_RECORD_SIZE_fd_set))
+	      {
+		return (-1);
+	      }
+	    if (record_arch_list_add_mem (sel.tvp, I386_RECORD_SIZE_timeval))
+	      {
+		return (-1);
+	      }
+	  }
+      }
+      break;
+
+      /* sys_symlink */
+    case 83:
+      break;
+
+      /* sys_readlink */
+    case 85:
+      {
+	uint32_t len;
+	regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			   (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			   (gdb_byte *) & len);
+	if (record_arch_list_add_mem (tmpu32, len))
+	  {
+	    return (-1);
+	  }
+      }
+      break;
+
+      /* sys_uselib */
+    case 86:
+      /* sys_swapon */
+    case 87:
+      break;
+
+      /* sys_reboot */
+    case 88:
+      {
+	int q;
+	target_terminal_ours ();
+	q =
+	  yquery (_
+		  ("The next instruction is syscall reboot. It will restart the computer. Do you want to pause the program."));
+	target_terminal_inferior ();
+	if (q)
+	  {
+	    return (1);
+	  }
+      }
+      break;
+
+      /* old_readdir */
+    case 89:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_dirent))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* old_mmap */
+    case 90:
+      break;
+
+      /* sys_munmap */
+    case 91:
+      {
+	int q;
+	uint32_t len;
+
+	regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			   (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			   (gdb_byte *) & len);
+	target_terminal_ours ();
+	q =
+	  yquery (_
+		  ("The next instruction is syscall munmap. It will free the memory addr = 0x%s len = %d. Do you want to pause the program."),
+		  paddr_nz (tmpu32), len);
+	target_terminal_inferior ();
+	if (q)
+	  {
+	    return (1);
+	  }
+      }
+      break;
+
+      /* sys_truncate */
+    case 92:
+      /* sys_ftruncate */
+    case 93:
+      /* sys_fchmod */
+    case 94:
+      /* sys_fchown16 */
+    case 95:
+      /* sys_getpriority */
+    case 96:
+      /* sys_setpriority */
+    case 97:
+      /* sys_ni_syscall */
+    case 98:
+      break;
+
+      /* sys_statfs */
+    case 99:
+      /* sys_fstatfs */
+    case 100:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_statfs))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_ioperm */
+    case 101:
+      break;
+
+      /* sys_socketcall */
+    case 102:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+	{
+	case I386_RECORD_SYS_SOCKET:
+	case I386_RECORD_SYS_BIND:
+	case I386_RECORD_SYS_CONNECT:
+	case I386_RECORD_SYS_LISTEN:
+	  break;
+	case I386_RECORD_SYS_ACCEPT:
+	case I386_RECORD_SYS_GETSOCKNAME:
+	case I386_RECORD_SYS_GETPEERNAME:
+	  {
+	    uint32_t a[3];
+	    regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			       (gdb_byte *) & tmpu32);
+	    if (tmpu32)
+	      {
+		if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+		  {
+		    fprintf_unfiltered (gdb_stdlog,
+					"Record: read memory addr = 0x%s len = %d error.\n",
+					paddr_nz (tmpu32), sizeof (a));
+		    return (-1);
+		  }
+		if (record_arch_list_add_mem (a[1], I386_RECORD_SIZE_sockaddr))
+		  {
+		    return (-1);
+		  }
+		if (record_arch_list_add_mem (a[2], I386_RECORD_SIZE_int))
+		  {
+		    return (-1);
+		  }
+	      }
+	  }
+	  break;
+
+	case I386_RECORD_SYS_SOCKETPAIR:
+	  {
+	    uint32_t a[4];
+	    regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			       (gdb_byte *) & tmpu32);
+	    if (tmpu32)
+	      {
+		if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+		  {
+		    fprintf_unfiltered (gdb_stdlog,
+					"Record: read memory addr = 0x%s len = %d error.\n",
+					paddr_nz (tmpu32), sizeof (a));
+		    return (-1);
+		  }
+		if (record_arch_list_add_mem (a[3], I386_RECORD_SIZE_int))
+		  {
+		    return (-1);
+		  }
+	      }
+	  }
+	  break;
+	case I386_RECORD_SYS_SEND:
+	case I386_RECORD_SYS_SENDTO:
+	  break;
+	case I386_RECORD_SYS_RECV:
+	  {
+	    uint32_t a[3];
+	    regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			       (gdb_byte *) & tmpu32);
+	    if (tmpu32)
+	      {
+		if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+		  {
+		    fprintf_unfiltered (gdb_stdlog,
+					"Record: read memory addr = 0x%s len = %d error.\n",
+					paddr_nz (tmpu32), sizeof (a));
+		    return (-1);
+		  }
+		if (a[2])
+		  {
+		    if (target_read_memory
+			(a[2], (gdb_byte *) & (a[2]), sizeof (a[2])))
+		      {
+			fprintf_unfiltered (gdb_stdlog,
+					    "Record: read memory addr = 0x%s len = %d error.\n",
+					    paddr_nz (a[2]), sizeof (a[2]));
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem (a[1], a[2]))
+		      {
+			return (-1);
+		      }
+		  }
+	      }
+	  }
+	  break;
+	case I386_RECORD_SYS_RECVFROM:
+	  {
+	    uint32_t a[6];
+	    regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			       (gdb_byte *) & tmpu32);
+	    if (tmpu32)
+	      {
+		if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+		  {
+		    fprintf_unfiltered (gdb_stdlog,
+					"Record: read memory addr = 0x%s len = %d error.\n",
+					paddr_nz (tmpu32), sizeof (a));
+		    return (-1);
+		  }
+		if (a[2])
+		  {
+		    if (target_read_memory
+			(a[2], (gdb_byte *) & (a[2]), sizeof (a[2])))
+		      {
+			fprintf_unfiltered (gdb_stdlog,
+					    "Record: read memory addr = 0x%s len = %d error.\n",
+					    paddr_nz (a[2]), sizeof (a[2]));
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem (a[1], a[2]))
+		      {
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem (a[4], I386_RECORD_SIZE_sockaddr))
+		      {
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem (a[5], I386_RECORD_SIZE_int))
+		      {
+			return (-1);
+		      }
+		  }
+	      }
+	  }
+	  break;
+	case I386_RECORD_SYS_SHUTDOWN:
+	case I386_RECORD_SYS_SETSOCKOPT:
+	  break;
+	case I386_RECORD_SYS_GETSOCKOPT:
+	  {
+	    uint32_t a[5];
+	    uint32_t av;
+
+	    regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			       (gdb_byte *) & tmpu32);
+	    if (tmpu32)
+	      {
+		if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+		  {
+		    fprintf_unfiltered (gdb_stdlog,
+					"Record: read memory addr = 0x%s len = %d error.\n",
+					paddr_nz (tmpu32), sizeof (a));
+		    return (-1);
+		  }
+		if (a[4])
+		  {
+		    if (target_read_memory
+			(a[4], (gdb_byte *) & av, sizeof (av)))
+		      {
+			fprintf_unfiltered (gdb_stdlog,
+					    "Record: read memory addr = 0x%s len = %d error.\n",
+					    paddr_nz (a[4]), sizeof (av));
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem (a[3], av))
+		      {
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem (a[4], I386_RECORD_SIZE_int))
+		      {
+			return (-1);
+		      }
+		  }
+	      }
+	  }
+	  break;
+	case I386_RECORD_SYS_SENDMSG:
+	  break;
+	case I386_RECORD_SYS_RECVMSG:
+	  {
+	    uint32_t a[2], i;
+	    struct record_msghdr
+	    {
+	      uint32_t msg_name;
+	      uint32_t msg_namelen;
+	      uint32_t msg_iov;
+	      uint32_t msg_iovlen;
+	      uint32_t msg_control;
+	      uint32_t msg_controllen;
+	      uint32_t msg_flags;
+	    } rec;
+	    struct record_iovec
+	    {
+	      uint32_t iov_base;
+	      uint32_t iov_len;
+	    } iov;
+
+	    regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			       (gdb_byte *) & tmpu32);
+	    if (tmpu32)
+	      {
+		if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+		  {
+		    fprintf_unfiltered (gdb_stdlog,
+					"Record: read memory addr = 0x%s len = %d error.\n",
+					paddr_nz (tmpu32), sizeof (a));
+		    return (-1);
+		  }
+		if (record_arch_list_add_mem (a[1], I386_RECORD_SIZE_msghdr))
+		  {
+		    return (-1);
+		  }
+		if (a[1])
+		  {
+		    if (target_read_memory
+			(a[1], (gdb_byte *) & rec, sizeof (rec)))
+		      {
+			fprintf_unfiltered (gdb_stdlog,
+					    "Record: read memory addr = 0x%s len = %d error.\n",
+					    paddr_nz (a[1]), sizeof (rec));
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem
+			(rec.msg_name, rec.msg_namelen))
+		      {
+			return (-1);
+		      }
+		    if (record_arch_list_add_mem
+			(rec.msg_control, rec.msg_controllen))
+		      {
+			return (-1);
+		      }
+		    if (rec.msg_iov)
+		      {
+			for (i = 0; i < rec.msg_iovlen; i++)
+			  {
+			    if (target_read_memory
+				(rec.msg_iov, (gdb_byte *) & iov,
+				 sizeof (iov)))
+			      {
+				fprintf_unfiltered (gdb_stdlog,
+						    "Record: read memory addr = 0x%s len = %d error.\n",
+						    paddr_nz (rec.msg_iov),
+						    sizeof (iov));
+				return (-1);
+			      }
+			    if (record_arch_list_add_mem
+				(iov.iov_base, iov.iov_len))
+			      {
+				return (-1);
+			      }
+			    rec.msg_iov += sizeof (struct record_iovec);
+			  }
+		      }
+		  }
+	      }
+	  }
+	  break;
+	default:
+	  printf_unfiltered (_
+			     ("Record: record and reverse function don't support socketcall call 0x%08x\n"),
+			     tmpu32);
+	  return (-1);
+	  break;
+	}
+      break;
+
+      /* sys_syslog */
+    case 103:
+      break;
+
+      /* sys_setitimer */
+    case 104:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerval))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_getitimer */
+    case 105:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerval))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_newstat */
+    case 106:
+      /* sys_newlstat */
+    case 107:
+      /* sys_newfstat */
+    case 108:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stat))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_uname */
+    case 109:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_utsname))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_iopl */
+    case 110:
+      /* sys_vhangup */
+    case 111:
+      /* sys_ni_syscall */
+    case 112:
+      /* sys_vm86old */
+    case 113:
+      break;
+
+      /* sys_wait4 */
+    case 114:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rusage))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_swapoff */
+    case 115:
+      break;
+
+      /* sys_sysinfo */
+    case 116:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_sysinfo))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_ipc */
+    case 117:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+	{
+	case I386_RECORD_MSGRCV:
+	  {
+	    int32_t second;
+	    uint32_t ptr;
+	    regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			       (gdb_byte *) & second);
+	    regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			       (gdb_byte *) & ptr);
+	    if (record_arch_list_add_mem (ptr, second + I386_RECORD_SIZE_long))
+	      {
+		return (-1);
+	      }
+	  }
+	  break;
+	case I386_RECORD_MSGCTL:
+	  regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_msqid_ds))
+	    {
+	      return (-1);
+	    }
+	  break;
+	case I386_RECORD_SHMAT:
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_ulong))
+	    {
+	      return (-1);
+	    }
+	  break;
+	case I386_RECORD_SHMCTL:
+	  regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_shmid_ds))
+	    {
+	      return (-1);
+	    }
+	  break;
+	}
+      break;
+
+      /* sys_fsync */
+    case 118:
+      /* sys_sigreturn */
+    case 119:
+      /* sys_clone */
+    case 120:
+      /* sys_setdomainname */
+    case 121:
+      break;
+
+      /* sys_newuname */
+    case 122:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_new_utsname))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_modify_ldt */
+    case 123:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32 == 0 || tmpu32 == 2)
+	{
+	  uint32_t ptr, bytecount;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & ptr);
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & bytecount);
+	  if (record_arch_list_add_mem (ptr, bytecount))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_adjtimex */
+    case 124:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timex))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_mprotect */
+    case 125:
+      break;
+
+      /* sys_sigprocmask */
+    case 126:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_sigset_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_ni_syscall */
+    case 127:
+      /* sys_init_module */
+    case 128:
+      /* sys_delete_module */
+    case 129:
+      /* sys_ni_syscall */
+    case 130:
+      break;
+
+      /* sys_quotactl */
+    case 131:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+	{
+	case I386_RECORD_Q_GETFMT:
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, 4))
+	    {
+	      return (-1);
+	    }
+	  break;
+	case I386_RECORD_Q_GETINFO:
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_mem_dqinfo))
+	    {
+	      return (-1);
+	    }
+	  break;
+	case I386_RECORD_Q_GETQUOTA:
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_if_dqblk))
+	    {
+	      return (-1);
+	    }
+	  break;
+	case I386_RECORD_Q_XGETQSTAT:
+	case I386_RECORD_Q_XGETQUOTA:
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fs_quota_stat))
+	    {
+	      return (-1);
+	    }
+	  break;
+	}
+      break;
+
+      /* sys_getpgid */
+    case 132:
+      /* sys_fchdir */
+    case 133:
+      /* sys_bdflush */
+    case 134:
+      break;
+
+      /* sys_sysfs */
+    case 135:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32 == 2)
+	{
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  /*XXX the size of memory is not very clear */
+	  if (record_arch_list_add_mem (tmpu32, 10))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_personality */
+    case 136:
+      /* sys_ni_syscall */
+    case 137:
+      /* sys_setfsuid16 */
+    case 138:
+      /* sys_setfsgid16 */
+    case 139:
+      break;
+
+      /* sys_llseek */
+    case 140:
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_getdents */
+    case 141:
+      {
+	uint32_t count;
+	regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			   (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			   (gdb_byte *) & count);
+	if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_dirent * count))
+	  {
+	    return (-1);
+	  }
+      }
+      break;
+
+      /* sys_select */
+    case 142:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timeval))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_flock */
+    case 143:
+      /* sys_msync */
+    case 144:
+      break;
+
+      /* sys_readv */
+    case 145:
+      {
+	uint32_t vec;
+	uint32_t vlen;
+	struct record_iovec
+	{
+	  uint32_t iov_base;
+	  uint32_t iov_len;
+	} iov;
+	regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			   (gdb_byte *) & vec);
+	if (vec)
+	  {
+	    regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			       (gdb_byte *) & vlen);
+	    for (tmpu32 = 0; tmpu32 < vlen; tmpu32++)
+	      {
+		if (target_read_memory
+		    (vec, (gdb_byte *) & iov, sizeof (struct record_iovec)))
+		  {
+		    fprintf_unfiltered (gdb_stdlog,
+					"Record: read memory addr = 0x%s len = %d error.\n",
+					paddr_nz (vec),
+					sizeof (struct record_iovec));
+		    return (-1);
+		  }
+		if (record_arch_list_add_mem (iov.iov_base, iov.iov_len))
+		  {
+		    return (-1);
+		  }
+		vec += sizeof (struct record_iovec);
+	      }
+	  }
+      }
+      break;
+
+      /* sys_writev */
+    case 146:
+      /* sys_getsid */
+    case 147:
+      /* sys_fdatasync */
+    case 148:
+      /* sys_sysctl */
+    case 149:
+      /* sys_mlock */
+    case 150:
+      /* sys_munlock */
+    case 151:
+      /* sys_mlockall */
+    case 152:
+      /* sys_munlockall */
+    case 153:
+      /* sys_sched_setparam */
+    case 154:
+      break;
+
+      /* sys_sched_getparam */
+    case 155:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_sched_setscheduler */
+    case 156:
+      /* sys_sched_getscheduler */
+    case 157:
+      /* sys_sched_yield */
+    case 158:
+      /* sys_sched_get_priority_max */
+    case 159:
+      /* sys_sched_get_priority_min */
+    case 160:
+      break;
+
+      /* sys_sched_rr_get_interval */
+    case 161:
+      /* sys_nanosleep */
+    case 162:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_mremap */
+    case 163:
+      /* sys_setresuid16 */
+    case 164:
+      break;
+
+      /* sys_getresuid16 */
+    case 165:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_uid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_uid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_uid_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_vm86 */
+    case 166:
+      /* sys_ni_syscall */
+    case 167:
+      break;
+
+      /* sys_poll */
+    case 168:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t nfds;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & nfds);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_pollfd * nfds))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_nfsservctl */
+    case 169:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32 == 7 || tmpu32 == 8)
+	{
+	  uint32_t rsize;
+	  if (tmpu32 == 7)
+	    {
+	      rsize = I386_RECORD_SIZE_NFS_FHSIZE;
+	    }
+	  else
+	    {
+	      rsize = I386_RECORD_SIZE_knfsd_fh;
+	    }
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, rsize))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_setresgid16 */
+    case 170:
+      break;
+
+      /* sys_getresgid16 */
+    case 171:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_prctl */
+    case 172:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+	{
+	case 2:
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	    {
+	      return (-1);
+	    }
+	  break;
+	case 16:
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_TASK_COMM_LEN))
+	    {
+	      return (-1);
+	    }
+	  break;
+	}
+      break;
+
+      /* sys_rt_sigreturn */
+    case 173:
+      break;
+
+      /* sys_rt_sigaction */
+    case 174:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_sigaction))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_rt_sigprocmask */
+    case 175:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_sigset_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_rt_sigpending */
+    case 176:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t sigsetsize;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & sigsetsize);
+	  if (record_arch_list_add_mem (tmpu32, sigsetsize))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_rt_sigtimedwait */
+    case 177:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_siginfo_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_rt_sigqueueinfo */
+    case 178:
+      /* sys_rt_sigsuspend */
+    case 179:
+      break;
+
+      /* sys_pread64 */
+    case 180:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t count;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & count);
+	  if (record_arch_list_add_mem (tmpu32, count))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_pwrite64 */
+    case 181:
+      /* sys_chown16 */
+    case 182:
+      break;
+
+      /* sys_getcwd */
+    case 183:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t size;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & size);
+	  if (record_arch_list_add_mem (tmpu32, size))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_capget */
+    case 184:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_cap_user_data_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_capset */
+    case 185:
+      break;
+
+      /* sys_sigaltstack */
+    case 186:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stack_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_sendfile */
+    case 187:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_off_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_ni_syscall */
+    case 188:
+      /* sys_ni_syscall */
+    case 189:
+      /* sys_vfork */
+    case 190:
+      break;
+
+      /* sys_getrlimit */
+    case 191:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rlimit))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_mmap2 */
+    case 192:
+      break;
+
+      /* sys_truncate64 */
+    case 193:
+      /* sys_ftruncate64 */
+    case 194:
+      break;
+
+      /* sys_stat64 */
+    case 195:
+      /* sys_lstat64 */
+    case 196:
+      /* sys_fstat64 */
+    case 197:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stat64))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_lchown */
+    case 198:
+      /* sys_getuid */
+    case 199:
+      /* sys_getgid */
+    case 200:
+      /* sys_geteuid */
+    case 201:
+      /* sys_getegid */
+    case 202:
+      /* sys_setreuid */
+    case 203:
+      /* sys_setregid */
+    case 204:
+      break;
+
+      /* sys_getgroups */
+    case 205:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  int gidsetsize;
+	  regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			     (gdb_byte *) & gidsetsize);
+	  if (record_arch_list_add_mem
+	      (tmpu32, I386_RECORD_SIZE_gid_t * gidsetsize))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_setgroups */
+    case 206:
+      /* sys_fchown */
+    case 207:
+      /* sys_setresuid */
+    case 208:
+      break;
+
+      /* sys_getresuid */
+    case 209:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_uid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_uid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_uid_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_setresgid */
+    case 210:
+      break;
+
+      /* sys_getresgid */
+    case 211:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_gid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_gid_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_gid_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_chown */
+    case 212:
+      /* sys_setuid */
+    case 213:
+      /* sys_setgid */
+    case 214:
+      /* sys_setfsuid */
+    case 215:
+      /* sys_setfsgid */
+    case 216:
+      /* sys_pivot_root */
+    case 217:
+      break;
+
+      /* sys_mincore */
+    case 218:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_PAGE_SIZE))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_madvise */
+    case 219:
+      break;
+
+      /* sys_getdents64 */
+    case 220:
+      {
+	uint32_t count;
+	regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			   (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			   (gdb_byte *) & count);
+	if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_dirent64 * count))
+	  {
+	    return (-1);
+	  }
+      }
+      break;
+
+      /* sys_fcntl64 */
+    case 221:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+	{
+	case F_GETLK64:
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_flock64))
+	    {
+	      return (-1);
+	    }
+	  break;
+	case F_SETLK64:
+	case F_SETLKW64:
+	  break;
+	default:
+	  goto sys_fcntl;
+	  break;
+	}
+      break;
+
+      /* sys_ni_syscall */
+    case 222:
+      /* sys_ni_syscall */
+    case 223:
+      /* sys_gettid */
+    case 224:
+      /* sys_readahead */
+    case 225:
+      /* sys_setxattr */
+    case 226:
+      /* sys_lsetxattr */
+    case 227:
+      /* sys_fsetxattr */
+    case 228:
+      break;
+
+      /* sys_getxattr */
+    case 229:
+      /* sys_lgetxattr */
+    case 230:
+      /* sys_fgetxattr */
+    case 231:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t size;
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & size);
+	  if (record_arch_list_add_mem (tmpu32, size))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_listxattr */
+    case 232:
+      /* sys_llistxattr */
+    case 233:
+      /* sys_flistxattr */
+    case 234:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t size;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & size);
+	  if (record_arch_list_add_mem (tmpu32, size))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_removexattr */
+    case 235:
+      /* sys_lremovexattr */
+    case 236:
+      /* sys_fremovexattr */
+    case 237:
+      /* sys_tkill */
+    case 238:
+      break;
+
+      /* sys_sendfile64 */
+    case 239:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_futex */
+    case 240:
+      /* sys_sched_setaffinity */
+    case 241:
+      break;
+
+      /* sys_sched_getaffinity */
+    case 242:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t len;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & len);
+	  if (record_arch_list_add_mem (tmpu32, len))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_set_thread_area */
+    case 243:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_get_thread_area */
+    case 244:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_user_desc))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_io_setup */
+    case 245:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_long))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_io_destroy */
+    case 246:
+      break;
+
+      /* sys_io_getevents */
+    case 247:
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  int32_t nr;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & nr);
+	  if (record_arch_list_add_mem (tmpu32, nr * I386_RECORD_SIZE_io_event))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_io_submit */
+    case 248:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  int32_t i, nr;
+	  uint32_t *iocbp;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & nr);
+	  iocbp = (uint32_t *) alloca (nr * I386_RECORD_SIZE_int);
+	  if (target_read_memory
+	      (tmpu32, (gdb_byte *) iocbp, nr * I386_RECORD_SIZE_int))
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "Record: read memory addr = 0x%s len = %d error.\n",
+				  paddr_nz (tmpu32), nr * I386_RECORD_SIZE_int);
+	      return (-1);
+	    }
+	  for (i = 0; i < nr; i++)
+	    {
+	      if (record_arch_list_add_mem (iocbp[i], I386_RECORD_SIZE_iocb))
+		{
+		  return (-1);
+		}
+	    }
+	}
+      break;
+
+      /* sys_io_cancel */
+    case 249:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_io_event))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_fadvise64 */
+    case 250:
+      /* sys_ni_syscall */
+    case 251:
+      break;
+
+      /* sys_exit_group */
+    case 252:
+      {
+	int q;
+	target_terminal_ours ();
+	q =
+	  yquery (_
+		  ("The next instruction is syscall exit_group. It will make the program exit. Do you want to pause the program."));
+	target_terminal_inferior ();
+	if (q)
+	  {
+	    return (1);
+	  }
+      }
+      break;
+
+      /* sys_lookup_dcookie */
+    case 253:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t len;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & len);
+	  if (record_arch_list_add_mem (tmpu32, len))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_epoll_create */
+    case 254:
+      /* sys_epoll_ctl */
+    case 255:
+      break;
+
+      /* sys_epoll_wait */
+    case 256:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  int32_t maxevents;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & maxevents);
+	  if (record_arch_list_add_mem
+	      (tmpu32, maxevents * I386_RECORD_SIZE_epoll_event))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_remap_file_pages */
+    case 257:
+      /* sys_set_tid_address */
+    case 258:
+      break;
+
+      /* sys_timer_create */
+    case 259:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_timer_settime */
+    case 260:
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerspec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_timer_gettime */
+    case 261:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerspec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_timer_getoverrun */
+    case 262:
+      /* sys_timer_delete */
+    case 263:
+      /* sys_clock_settime */
+    case 264:
+      break;
+
+      /* sys_clock_gettime */
+    case 265:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_clock_getres */
+    case 266:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_clock_nanosleep */
+    case 267:
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_statfs64 */
+    case 268:
+      /* sys_fstatfs64 */
+    case 269:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_statfs64))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_tgkill */
+    case 270:
+      /* sys_utimes */
+    case 271:
+      /* sys_fadvise64_64 */
+    case 272:
+      /* sys_ni_syscall */
+    case 273:
+      /* sys_mbind */
+    case 274:
+      break;
+
+      /* sys_get_mempolicy */
+    case 275:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t maxnode;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & maxnode);
+	  if (record_arch_list_add_mem (tmpu32, maxnode * I386_RECORD_SIZE_long))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_set_mempolicy */
+    case 276:
+      /* sys_mq_open */
+    case 277:
+      /* sys_mq_unlink */
+    case 278:
+      /* sys_mq_timedsend */
+    case 279:
+      break;
+
+      /* sys_mq_timedreceive */
+    case 280:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t msg_len;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & msg_len);
+	  if (record_arch_list_add_mem (tmpu32, msg_len))
+	    {
+	      return (-1);
+	    }
+	}
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_mq_notify */
+    case 281:
+      break;
+
+      /* sys_mq_getsetattr */
+    case 282:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_mq_attr))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_kexec_load */
+    case 283:
+      break;
+
+      /* sys_waitid */
+    case 284:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_siginfo))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rusage))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_ni_syscall */
+    case 285:
+      /* sys_add_key */
+    case 286:
+      /* sys_request_key */
+    case 287:
+      break;
+
+      /* sys_keyctl */
+    case 288:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32 == 6 || tmpu32 == 11)
+	{
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32)
+	    {
+	      uint32_t buflen;
+	      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+				 (gdb_byte *) & buflen);
+	      if (record_arch_list_add_mem (tmpu32, buflen))
+		{
+		  return (-1);
+		}
+	    }
+	}
+      break;
+
+      /* sys_ioprio_set */
+    case 289:
+      /* sys_ioprio_get */
+    case 290:
+      /* sys_inotify_init */
+    case 291:
+      /* sys_inotify_add_watch */
+    case 292:
+      /* sys_inotify_rm_watch */
+    case 293:
+      /* sys_migrate_pages */
+    case 294:
+      /* sys_openat */
+    case 295:
+      /* sys_mkdirat */
+    case 296:
+      /* sys_mknodat */
+    case 297:
+      /* sys_fchownat */
+    case 298:
+      /* sys_futimesat */
+    case 299:
+      break;
+
+      /* sys_fstatat64 */
+    case 300:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stat64))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_unlinkat */
+    case 301:
+      /* sys_renameat */
+    case 302:
+      /* sys_linkat */
+    case 303:
+      /* sys_symlinkat */
+    case 304:
+      break;
+
+      /* sys_readlinkat */
+    case 305:
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  int32_t bufsiz;
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & bufsiz);
+	  if (record_arch_list_add_mem (tmpu32, bufsiz))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_fchmodat */
+    case 306:
+      /* sys_faccessat */
+    case 307:
+      break;
+
+      /* sys_pselect6 */
+    case 308:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_ppoll */
+    case 309:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t nfds;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & nfds);
+	  if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_pollfd * nfds))
+	    {
+	      return (-1);
+	    }
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_unshare */
+    case 310:
+      /* sys_set_robust_list */
+    case 311:
+      break;
+
+      /* sys_get_robust_list */
+    case 312:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_splice */
+    case 313:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_sync_file_range */
+    case 314:
+      /* sys_tee */
+    case 315:
+      /* sys_vmsplice */
+    case 316:
+      break;
+
+      /* sys_move_pages */
+    case 317:
+      regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  uint32_t nr_pages;
+	  regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			     (gdb_byte *) & nr_pages);
+	  if (record_arch_list_add_mem (tmpu32, nr_pages * I386_RECORD_SIZE_int))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* sys_getcpu */
+    case 318:
+      regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_ulong * 2))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sys_epoll_pwait */
+    case 319:
+      regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (tmpu32)
+	{
+	  int32_t maxevents;
+	  regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+			     (gdb_byte *) & maxevents);
+	  if (record_arch_list_add_mem
+	      (tmpu32, maxevents * I386_RECORD_SIZE_epoll_event))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+    default:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support syscall number 0x%08x\n"),
+			 tmpu32);
+      return (-1);
+      break;
+    }
+  if (record_arch_list_add_reg (I386_EAX_REGNUM))
+    {
+      return (-1);
+    }
+
+  return (0);
+}
 
 /* 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
@@ -440,6 +2967,9 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->sc_reg_offset = i386_linux_sc_reg_offset;
   tdep->sc_num_regs = ARRAY_SIZE (i386_linux_sc_reg_offset);
 
+  tdep->i386_intx80_record = i386_linux_intx80_sysenter_record;
+  tdep->i386_sysenter_record = i386_linux_intx80_sysenter_record;
+
   /* N_FUN symbols in shared libaries have 0 for their values and need
      to be relocated. */
   set_gdbarch_sofun_address_maybe_missing (gdbarch, 1);
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index be4f4f3..fa1f282 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -49,6 +49,9 @@
 #include "i386-tdep.h"
 #include "i387-tdep.h"
 
+#include "record.h"
+#include <stdint.h>
+
 /* Register names.  */
 
 static char *i386_register_names[] =
@@ -2450,6 +2453,2529 @@ i386_fetch_pointer_argument (struct frame_info *frame, int argi,
   return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
 }
 
+#define PREFIX_REPZ	0x01
+#define PREFIX_REPNZ	0x02
+#define PREFIX_LOCK	0x04
+#define PREFIX_DATA	0x08
+#define PREFIX_ADDR	0x10
+
+/* operand size */
+enum
+{
+  OT_BYTE = 0,
+  OT_WORD,
+  OT_LONG,
+};
+
+/* i386 arith/logic operations */
+enum
+{
+  OP_ADDL,
+  OP_ORL,
+  OP_ADCL,
+  OP_SBBL,
+  OP_ANDL,
+  OP_SUBL,
+  OP_XORL,
+  OP_CMPL,
+};
+
+static int aflag = 1;
+static int dflag = 1;
+static int override = 0;
+static uint8_t modrm;
+static uint8_t mod, reg, rm;
+static int ot;
+static CORE_ADDR i386_record_pc;
+
+/* Parse "modrm" part in current memory address that i386_record_pc point to.
+   Return -1 if something wrong. */
+static int
+i386_record_modrm (void)
+{
+  if (target_read_memory (i386_record_pc, &modrm, 1))
+    {
+      printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+			 paddr_nz (i386_record_pc));
+      return (-1);
+    }
+  i386_record_pc++;
+  mod = (modrm >> 6) & 3;
+  reg = (modrm >> 3) & 7;
+  rm = modrm & 7;
+
+  return (0);
+}
+
+/* Get the memory address that current instruction  write to and set it to
+   the argument "addr".
+   Return -1 if something wrong. */
+static int
+i386_record_lea_modrm_addr (uint32_t * addr)
+{
+  uint8_t tmpu8;
+  uint16_t tmpu16;
+  uint32_t tmpu32;
+
+  *addr = 0;
+  if (aflag)
+    {
+      /* 32 bits */
+      int havesib = 0;
+      uint8_t scale = 0;
+      uint8_t index = 0;
+      uint8_t base = rm;
+
+      if (base == 4)
+	{
+	  havesib = 1;
+	  if (target_read_memory (i386_record_pc, &tmpu8, 1))
+	    {
+	      printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				 paddr_nz (i386_record_pc));
+	      return (-1);
+	    }
+	  i386_record_pc++;
+	  scale = (tmpu8 >> 6) & 3;
+	  index = ((tmpu8 >> 3) & 7);
+	  base = (tmpu8 & 7);
+	}
+
+      switch (mod)
+	{
+	case 0:
+	  if ((base & 7) == 5)
+	    {
+	      base = 0xff;
+	      if (target_read_memory (i386_record_pc, (gdb_byte *) addr, 4))
+		{
+		  printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				     paddr_nz (i386_record_pc));
+		  return (-1);
+		}
+	      i386_record_pc += 4;
+	    }
+	  else
+	    {
+	      *addr = 0;
+	    }
+	  break;
+	case 1:
+	  if (target_read_memory (i386_record_pc, &tmpu8, 1))
+	    {
+	      printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				 paddr_nz (i386_record_pc));
+	      return (-1);
+	    }
+	  i386_record_pc++;
+	  *addr = (int8_t) tmpu8;
+	  break;
+	case 2:
+	  if (target_read_memory (i386_record_pc, (gdb_byte *) addr, 4))
+	    {
+	      printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				 paddr_nz (i386_record_pc));
+	      return (-1);
+	    }
+	  i386_record_pc += 4;
+	  break;
+	}
+
+      if (base != 0xff)
+	{
+	  regcache_raw_read (record_regcache, base, (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	}
+
+      /* XXX: index == 4 is always invalid */
+      if (havesib && (index != 4 || scale != 0))
+	{
+	  regcache_raw_read (record_regcache, index, (gdb_byte *) & tmpu32);
+	  *addr += tmpu32 << scale;
+	}
+    }
+  else
+    {
+      /* 16 bits */
+      switch (mod)
+	{
+	case 0:
+	  if (rm == 6)
+	    {
+	      if (target_read_memory
+		  (i386_record_pc, (gdb_byte *) & tmpu16, 2))
+		{
+		  printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				     paddr_nz (i386_record_pc));
+		  return (-1);
+		}
+	      i386_record_pc += 2;
+	      *addr = (int16_t) tmpu16;
+	      rm = 0;
+	      goto no_rm;
+	    }
+	  else
+	    {
+	      *addr = 0;
+	    }
+	  break;
+	case 1:
+	  if (target_read_memory (i386_record_pc, &tmpu8, 1))
+	    {
+	      printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				 paddr_nz (i386_record_pc));
+	      return (-1);
+	    }
+	  i386_record_pc++;
+	  *addr = (int8_t) tmpu8;
+	  break;
+	case 2:
+	  if (target_read_memory (i386_record_pc, (gdb_byte *) & tmpu16, 2))
+	    {
+	      printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				 paddr_nz (i386_record_pc));
+	      return (-1);
+	    }
+	  i386_record_pc += 2;
+	  *addr = (int16_t) tmpu16;
+	  break;
+	}
+
+      switch (rm)
+	{
+	case 0:
+	  regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	case 1:
+	  regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	case 2:
+	  regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	case 3:
+	  regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	case 4:
+	  regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	case 5:
+	  regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	case 6:
+	  regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	case 7:
+	  regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	  break;
+	}
+      *addr &= 0xffff;
+    }
+
+no_rm:
+  return (0);
+}
+
+/* Record the value of the memory that willbe changed in current instruction
+   to "record_arch_list".
+   Return -1 if something wrong. */
+static int
+i386_record_lea_modrm (void)
+{
+  uint32_t addr;
+
+  if (override)
+    {
+      printf_unfiltered (_
+			 ("Record: cann't get the value of the segment register in address 0x%s. Record ignore this change.\n"),
+			 paddr_nz (read_pc ()));
+      return (0);
+    }
+
+  if (i386_record_lea_modrm_addr (&addr))
+    {
+      return (-1);
+    }
+
+  if (record_arch_list_add_mem (addr, 1 << ot))
+    {
+      return (-1);
+    }
+
+  return (0);
+}
+
+/* Parse the current instruction and record the values of the registers and
+   memory that will be changed in current instruction to "record_arch_list".
+   Return -1 if something wrong. */
+static int
+i386_record (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  int prefixes = 0;
+  uint8_t tmpu8;
+  uint16_t tmpu16;
+  uint32_t tmpu32;
+  uint32_t opcode;
+
+  i386_record_pc = addr;
+  aflag = 1;
+  dflag = 1;
+  override = 0;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: i386_record pc = 0x%s\n",
+			  paddr_nz (i386_record_pc));
+    }
+
+  /* prefixes */
+  while (1)
+    {
+      if (target_read_memory (i386_record_pc, &tmpu8, 1))
+	{
+	  printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+			     paddr_nz (i386_record_pc));
+	  return (-1);
+	}
+      i386_record_pc++;
+      switch (tmpu8)
+	{
+	case 0xf3:
+	  prefixes |= PREFIX_REPZ;
+	  break;
+	case 0xf2:
+	  prefixes |= PREFIX_REPNZ;
+	  break;
+	case 0xf0:
+	  prefixes |= PREFIX_LOCK;
+	  break;
+	case 0x2e:
+	  override = I386_CS_REGNUM;
+	  break;
+	case 0x36:
+	  override = I386_SS_REGNUM;
+	  break;
+	case 0x3e:
+	  override = I386_DS_REGNUM;
+	  break;
+	case 0x26:
+	  override = I386_ES_REGNUM;
+	  break;
+	case 0x64:
+	  override = I386_FS_REGNUM;
+	  break;
+	case 0x65:
+	  override = I386_GS_REGNUM;
+	  break;
+	case 0x66:
+	  prefixes |= PREFIX_DATA;
+	  break;
+	case 0x67:
+	  prefixes |= PREFIX_ADDR;
+	  break;
+	default:
+	  goto out_prefixes;
+	  break;
+	}
+    }
+out_prefixes:
+  if (prefixes & PREFIX_DATA)
+    {
+      dflag ^= 1;
+    }
+  if (prefixes & PREFIX_ADDR)
+    {
+      aflag ^= 1;
+    }
+
+  /* now check op code */
+  opcode = (uint32_t) tmpu8;
+reswitch:
+  switch (opcode)
+    {
+    case 0x0f:
+      if (target_read_memory (i386_record_pc, &tmpu8, 1))
+	{
+	  printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+			     paddr_nz (i386_record_pc));
+	  return (-1);
+	}
+      i386_record_pc++;
+      opcode = (uint16_t) tmpu8 | 0x0f00;
+      goto reswitch;
+      break;
+
+      /* arith & logic */
+    case 0x00 ... 0x05:
+    case 0x08 ... 0x0d:
+    case 0x10 ... 0x15:
+    case 0x18 ... 0x1d:
+    case 0x20 ... 0x25:
+    case 0x28 ... 0x2d:
+    case 0x30 ... 0x35:
+    case 0x38 ... 0x3d:
+      if (((opcode >> 3) & 7) != OP_CMPL)
+	{
+	  if ((opcode & 1) == 0)
+	    {
+	      ot = OT_BYTE;
+	    }
+	  else
+	    {
+	      ot = dflag + OT_WORD;
+	    }
+
+	  switch ((opcode >> 1) & 3)
+	    {
+	      /* OP Ev, Gv */
+	    case 0:
+	      if (i386_record_modrm ())
+		{
+		  return (-1);
+		}
+	      if (mod != 3)
+		{
+		  if (i386_record_lea_modrm ())
+		    {
+		      return (-1);
+		    }
+		}
+	      else
+		{
+		  if (ot == OT_BYTE)
+		    {
+		      rm &= 0x3;
+		    }
+		  if (record_arch_list_add_reg (rm))
+		    {
+		      return (-1);
+		    }
+		}
+	      break;
+	      /* OP Gv, Ev */
+	    case 1:
+	      if (i386_record_modrm ())
+		{
+		  return (-1);
+		}
+	      if (ot == OT_BYTE)
+		{
+		  reg &= 0x3;
+		}
+	      if (record_arch_list_add_reg (reg))
+		{
+		  return (-1);
+		}
+	      break;
+	      /* OP A, Iv */
+	    case 2:
+	      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+		{
+		  return (-1);
+		}
+	      break;
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* GRP1 */
+    case 0x80 ... 0x83:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+
+      if (reg != OP_CMPL)
+	{
+	  if ((opcode & 1) == 0)
+	    {
+	      ot = OT_BYTE;
+	    }
+	  else
+	    {
+	      ot = dflag + OT_WORD;
+	    }
+
+	  if (mod != 3)
+	    {
+	      if (i386_record_lea_modrm ())
+		{
+		  return (-1);
+		}
+	    }
+	  else
+	    {
+	      if (ot == OT_BYTE)
+		{
+		  reg &= 0x3;
+		}
+	      if (record_arch_list_add_reg (reg))
+		{
+		  return (-1);
+		}
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* inv */
+    case 0x40 ... 0x47:
+      /* dec */
+    case 0x48 ... 0x4f:
+      if (record_arch_list_add_reg (opcode & 7))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* GRP3 */
+    case 0xf6:
+    case 0xf7:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+
+      switch (reg)
+	{
+	  /* test */
+	case 0:
+	  if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  break;
+	  /* not */
+	case 2:
+	  if (mod != 3)
+	    {
+	      if (i386_record_lea_modrm ())
+		{
+		  return (-1);
+		}
+	    }
+	  else
+	    {
+	      if (ot == OT_BYTE)
+		{
+		  rm &= 0x3;
+		}
+	      if (record_arch_list_add_reg (rm))
+		{
+		  return (-1);
+		}
+	    }
+	  break;
+	  /* neg */
+	case 3:
+	  if (mod != 3)
+	    {
+	      if (i386_record_lea_modrm ())
+		{
+		  return (-1);
+		}
+	    }
+	  else
+	    {
+	      if (ot == OT_BYTE)
+		{
+		  rm &= 0x3;
+		}
+	      if (record_arch_list_add_reg (rm))
+		{
+		  return (-1);
+		}
+	    }
+	  if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  break;
+	  /* mul */
+	case 4:
+	  /* imul */
+	case 5:
+	  /* div */
+	case 6:
+	  /* idiv */
+	case 7:
+	  if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  if (ot != OT_BYTE)
+	    {
+	      if (record_arch_list_add_reg (I386_EDX_REGNUM))
+		{
+		  return (-1);
+		}
+	    }
+	  if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  break;
+	default:
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	  break;
+	}
+      break;
+
+      /* GRP4 */
+    case 0xfe:
+      /* GRP5 */
+    case 0xff:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (reg >= 2 && opcode == 0xfe)
+	{
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+
+      switch (reg)
+	{
+	  /* inc */
+	case 0:
+	  /* dec */
+	case 1:
+	  if (mod != 3)
+	    {
+	      if (i386_record_lea_modrm ())
+		{
+		  return (-1);
+		}
+	    }
+	  else
+	    {
+	      if (ot == OT_BYTE)
+		{
+		  rm &= 0x3;
+		}
+	      if (record_arch_list_add_reg (rm))
+		{
+		  return (-1);
+		}
+	    }
+	  if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  break;
+	  /* call */
+	case 2:
+	  /* push */
+	case 6:
+	  if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem
+	      ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+	    {
+	      return (-1);
+	    }
+	  break;
+	  /* lcall */
+	case 3:
+	  if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  if (record_arch_list_add_reg (I386_CS_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			     (gdb_byte *) & tmpu32);
+	  if (record_arch_list_add_mem
+	      ((CORE_ADDR) tmpu32 - (1 << (dflag + 2)), (1 << (dflag + 2))))
+	    {
+	      return (-1);
+	    }
+	  break;
+	  /* jmp */
+	case 4:
+	  /* ljmp */
+	case 5:
+	  break;
+	default:
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	  break;
+	}
+      break;
+
+      /* test */
+    case 0x84:
+    case 0x85:
+    case 0xa8:
+    case 0xa9:
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* CWDE/CBW */
+    case 0x98:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* CDQ/CWD */
+    case 0x99:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EDX_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* imul */
+    case 0x0faf:
+    case 0x69:
+    case 0x6b:
+      ot = dflag + OT_WORD;
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (ot == OT_BYTE)
+	{
+	  reg &= 0x3;
+	}
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* xadd */
+    case 0x0fc0:
+    case 0x0fc1:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  if (ot == OT_BYTE)
+	    {
+	      reg &= 0x3;
+	    }
+	  if (record_arch_list_add_reg (reg))
+	    {
+	      return (-1);
+	    }
+	  if (ot == OT_BYTE)
+	    {
+	      rm &= 0x3;
+	    }
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	  if (ot == OT_BYTE)
+	    {
+	      reg &= 0x3;
+	    }
+	  if (record_arch_list_add_reg (reg))
+	    {
+	      return (-1);
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* cmpxchg */
+    case 0x0fb0:
+    case 0x0fb1:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  if (ot == OT_BYTE)
+	    {
+	      reg &= 0x3;
+	    }
+	  if (record_arch_list_add_reg (reg))
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* cmpxchg8b */
+    case 0x0fc7:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EDX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (i386_record_lea_modrm ())
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* push */
+    case 0x50 ... 0x57:
+    case 0x68:
+    case 0x6a:
+      /* push es */
+    case 0x06:
+      /* push cs */
+    case 0x0e:
+      /* push ss */
+    case 0x16:
+      /* push ds */
+    case 0x1e:
+      /* push fs */
+    case 0x0fa0:
+      /* push gs */
+    case 0x0fa8:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+	  ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* pop */
+    case 0x58 ... 0x5f:
+      ot = dflag + OT_WORD;
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (ot == OT_BYTE)
+	{
+	  opcode &= 0x3;
+	}
+      if (record_arch_list_add_reg (opcode & 0x7))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* pusha */
+    case 0x60:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+	  ((CORE_ADDR) tmpu32 - (1 << (dflag + 4)), (1 << (dflag + 4))))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* popa */
+    case 0x61:
+      for (tmpu8 = I386_EAX_REGNUM; tmpu8 <= I386_EDI_REGNUM; tmpu8++)
+	{
+	  if (record_arch_list_add_reg (tmpu8))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* pop */
+    case 0x8f:
+      ot = dflag + OT_WORD;
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* enter */
+    case 0xc8:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EBP_REGNUM))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+	  ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* leave */
+    case 0xc9:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EBP_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* pop es */
+    case 0x07:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_ES_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* pop ss */
+    case 0x17:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_SS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* pop ds */
+    case 0x1f:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_DS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* pop fs */
+    case 0x0fa1:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_FS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* pop gs */
+    case 0x0fa9:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_GS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* mov */
+    case 0x88:
+    case 0x89:
+    case 0xc6:
+    case 0xc7:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+
+      if (mod != 3)
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (ot == OT_BYTE)
+	    {
+	      rm &= 0x3;
+	    }
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+      /* mov */
+    case 0x8a:
+    case 0x8b:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+
+      if (ot == OT_BYTE)
+	{
+	  reg &= 0x3;
+	}
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* mov seg */
+    case 0x8e:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+
+      switch (reg)
+	{
+	case 0:
+	  tmpu8 = I386_ES_REGNUM;
+	  break;
+	case 2:
+	  tmpu8 = I386_SS_REGNUM;
+	  break;
+	case 3:
+	  tmpu8 = I386_DS_REGNUM;
+	  break;
+	case 4:
+	  tmpu8 = I386_FS_REGNUM;
+	  break;
+	case 5:
+	  tmpu8 = I386_GS_REGNUM;
+	  break;
+	default:
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	  break;
+	}
+      if (record_arch_list_add_reg (tmpu8))
+	{
+	  return (-1);
+	}
+
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* mov seg */
+    case 0x8c:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (reg > 5)
+	{
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+
+      if (mod == 3)
+	{
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  ot = OT_WORD;
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* movzbS */
+    case 0x0fb6:
+      /* movzwS */
+    case 0x0fb7:
+      /* movsbS */
+    case 0x0fbe:
+      /* movswS */
+    case 0x0fbf:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* lea */
+    case 0x8d:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+
+      ot = dflag;
+      if (ot == OT_BYTE)
+	{
+	  reg &= 0x3;
+	}
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* mov EAX */
+    case 0xa0:
+    case 0xa1:
+      /* xlat */
+    case 0xd7:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* mov EAX */
+    case 0xa2:
+    case 0xa3:
+      {
+	uint32_t addr;
+
+	if ((opcode & 1) == 0)
+	  {
+	    ot = OT_BYTE;
+	  }
+	else
+	  {
+	    ot = dflag + OT_WORD;
+	  }
+	if (aflag)
+	  {
+	    if (target_read_memory (i386_record_pc, (gdb_byte *) & addr, 4))
+	      {
+		printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				   paddr_nz (i386_record_pc));
+		return (-1);
+	      }
+	    i386_record_pc += 4;
+	  }
+	else
+	  {
+	    if (target_read_memory (i386_record_pc, (gdb_byte *) & tmpu16, 4))
+	      {
+		printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+				   paddr_nz (i386_record_pc));
+		return (-1);
+	      }
+	    i386_record_pc += 2;
+	    addr = tmpu16;
+	  }
+	if (record_arch_list_add_mem (addr, 1 << ot))
+	  {
+	    return (-1);
+	  }
+      }
+      break;
+
+      /* mov R, Ib */
+    case 0xb0 ... 0xb7:
+      if (record_arch_list_add_reg ((opcode & 0x7) & 0x3))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* mov R, Iv */
+    case 0xb8 ... 0xbf:
+      if (record_arch_list_add_reg (opcode & 0x7))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* xchg R, EAX */
+    case 0x91 ... 0x97:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (opcode & 0x7))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* xchg Ev, Gv */
+    case 0x86:
+    case 0x87:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+
+      if (mod == 3)
+	{
+	  if (ot == OT_BYTE)
+	    {
+	      rm &= 0x3;
+	    }
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+
+      if (ot == OT_BYTE)
+	{
+	  reg &= 0x3;
+	}
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* les Gv */
+    case 0xc4:
+      /* lds Gv */
+    case 0xc5:
+      /* lss Gv */
+    case 0x0fb2:
+      /* lfs Gv */
+    case 0x0fb4:
+      /* lgs Gv */
+    case 0x0fb5:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  if (opcode > 0xff)
+	    {
+	      i386_record_pc -= 3;
+	    }
+	  else
+	    {
+	      i386_record_pc -= 2;
+	    }
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+
+      switch (opcode)
+	{
+	  /* les Gv */
+	case 0xc4:
+	  tmpu8 = I386_ES_REGNUM;
+	  break;
+	  /* lds Gv */
+	case 0xc5:
+	  tmpu8 = I386_DS_REGNUM;
+	  break;
+	  /* lss Gv */
+	case 0x0fb2:
+	  tmpu8 = I386_SS_REGNUM;
+	  break;
+	  /* lfs Gv */
+	case 0x0fb4:
+	  tmpu8 = I386_FS_REGNUM;
+	  break;
+	  /* lgs Gv */
+	case 0x0fb5:
+	  tmpu8 = I386_GS_REGNUM;
+	  break;
+	}
+      if (record_arch_list_add_reg (tmpu8))
+	{
+	  return (-1);
+	}
+
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* shifts */
+    case 0xc0:
+    case 0xc1:
+    case 0xd0:
+    case 0xd1:
+    case 0xd2:
+    case 0xd3:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+
+      if (mod != 3 && (opcode == 0xd2 || opcode == 0xd3))
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (ot == OT_BYTE)
+	    {
+	      rm &= 0x3;
+	    }
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+    case 0x0fa4:
+    case 0x0fa5:
+    case 0x0fac:
+    case 0x0fad:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* floats */
+      /* XXX */
+
+      /* string ops */
+      /* movsS */
+    case 0xa4:
+    case 0xa5:
+      /* stosS */
+    case 0xaa:
+    case 0xab:
+      /* insS */
+    case 0x6c:
+    case 0x6d:
+      {
+	uint32_t addr;
+
+	if ((opcode & 1) == 0)
+	  {
+	    ot = OT_BYTE;
+	  }
+	else
+	  {
+	    ot = dflag + OT_WORD;
+	  }
+	if (opcode == 0xa4 || opcode == 0xa5)
+	  {
+	    if (record_arch_list_add_reg (I386_ESI_REGNUM))
+	      {
+		return (-1);
+	      }
+	  }
+	if (record_arch_list_add_reg (I386_EDI_REGNUM))
+	  {
+	    return (-1);
+	  }
+
+	regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+			   (gdb_byte *) & addr);
+	if (!aflag)
+	  {
+	    addr &= 0xffff;
+	    /* addr += ((uint32_t)read_register (I386_ES_REGNUM)) << 4; */
+	    printf_unfiltered (_
+			       ("Record: cann't get the value of the segment register.\n"));
+	    return (-1);
+	  }
+
+	if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+	  {
+	    uint32_t count;
+
+	    regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+			       (gdb_byte *) & count);
+	    if (!aflag)
+	      {
+		count &= 0xffff;
+	      }
+
+	    regcache_raw_read (record_regcache, I386_EFLAGS_REGNUM,
+			       (gdb_byte *) & tmpu32);
+	    if ((tmpu32 >> 10) & 0x1)
+	      {
+		addr -= (count - 1) * (1 << ot);
+	      }
+
+	    if (record_arch_list_add_mem (addr, count * (1 << ot)))
+	      {
+		return (-1);
+	      }
+
+	    if (record_arch_list_add_reg (I386_ECX_REGNUM))
+	      {
+		return (-1);
+	      }
+	  }
+	else
+	  {
+	    if (record_arch_list_add_mem (addr, 1 << ot))
+	      {
+		return (-1);
+	      }
+	  }
+      }
+      break;
+
+      /* lodsS */
+    case 0xac:
+    case 0xad:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_ESI_REGNUM))
+	{
+	  return (-1);
+	}
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+	{
+	  if (record_arch_list_add_reg (I386_ECX_REGNUM))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* outsS */
+    case 0x6e:
+    case 0x6f:
+      if (record_arch_list_add_reg (I386_ESI_REGNUM))
+	{
+	  return (-1);
+	}
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+	{
+	  if (record_arch_list_add_reg (I386_ECX_REGNUM))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* scasS */
+    case 0xae:
+    case 0xaf:
+      if (record_arch_list_add_reg (I386_EDI_REGNUM))
+	{
+	  return (-1);
+	}
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+	{
+	  if (record_arch_list_add_reg (I386_ECX_REGNUM))
+	    {
+	      return (-1);
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* cmpsS */
+    case 0xa6:
+    case 0xa7:
+      if (record_arch_list_add_reg (I386_EDI_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_ESI_REGNUM))
+	{
+	  return (-1);
+	}
+      if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+	{
+	  if (record_arch_list_add_reg (I386_ECX_REGNUM))
+	    {
+	      return (-1);
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* port I/O */
+    case 0xe4:
+    case 0xe5:
+    case 0xec:
+    case 0xed:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+    case 0xe6:
+    case 0xe7:
+    case 0xee:
+    case 0xef:
+      break;
+
+      /* control */
+      /* ret im */
+    case 0xc2:
+      /* ret */
+    case 0xc3:
+      /* lret im */
+    case 0xca:
+      /* lret */
+    case 0xcb:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_CS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* iret */
+    case 0xcf:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_CS_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* call im */
+    case 0xe8:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+	  ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* lcall im */
+    case 0x9a:
+      if (record_arch_list_add_reg (I386_CS_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+	  ((CORE_ADDR) tmpu32 - (1 << (dflag + 2)), (1 << (dflag + 2))))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* jmp im */
+    case 0xe9:
+      /* ljmp im */
+    case 0xea:
+      /* jmp Jb */
+    case 0xeb:
+      /* jcc Jb */
+    case 0x70 ... 0x7f:
+      /* jcc Jv */
+    case 0x0f80 ... 0x0f8f:
+      break;
+
+      /* setcc Gv */
+    case 0x0f90 ... 0x0f9f:
+      ot = OT_BYTE;
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod == 3)
+	{
+	  if (record_arch_list_add_reg (rm & 0x3))
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* cmov Gv, Ev */
+    case 0x0f40 ... 0x0f4f:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (dflag == OT_BYTE)
+	{
+	  reg &= 0x3;
+	}
+      if (record_arch_list_add_reg (reg & 0x3))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* flags */
+      /* pushf */
+    case 0x9c:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+			 (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem
+	  ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* popf */
+    case 0x9d:
+      if (record_arch_list_add_reg (I386_ESP_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* sahf */
+    case 0x9e:
+      /* cmc */
+    case 0xf5:
+      /* clc */
+    case 0xf8:
+      /* stc */
+    case 0xf9:
+      /* cld */
+    case 0xfc:
+      /* std */
+    case 0xfd:
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* lahf */
+    case 0x9f:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* bit operations */
+      /* bt/bts/btr/btc Gv, im */
+    case 0x0fba:
+      /* bts */
+    case 0x0fab:
+      /* btr */
+    case 0x0fb3:
+      /* btc */
+    case 0x0fbb:
+      ot = dflag + OT_WORD;
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (reg < 4)
+	{
+	  i386_record_pc -= 3;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+      reg -= 4;
+      if (reg != 0)
+	{
+	  if (mod != 3)
+	    {
+	      if (i386_record_lea_modrm ())
+		{
+		  return (-1);
+		}
+	    }
+	  else
+	    {
+	      if (record_arch_list_add_reg (rm))
+		{
+		  return (-1);
+		}
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* bt Gv, Ev */
+    case 0x0fa3:
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* bsf */
+    case 0x0fbc:
+      /* bsr */
+    case 0x0fbd:
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* bcd */
+      /* daa */
+    case 0x27:
+      /* das */
+    case 0x2f:
+      /* aaa */
+    case 0x37:
+      /* aas */
+    case 0x3f:
+      /* aam */
+    case 0xd4:
+      /* aad */
+    case 0xd5:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* misc */
+      /* nop */
+    case 0x90:
+      if (prefixes & PREFIX_LOCK)
+	{
+	  i386_record_pc -= 1;
+	  goto no_support;
+	}
+      break;
+
+      /* fwait */
+      /* XXX */
+    case 0x9b:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction fwait.\n"));
+      i386_record_pc -= 1;
+      goto no_support;
+      break;
+
+      /* int3 */
+      /* XXX */
+    case 0xcc:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction int3.\n"));
+      i386_record_pc -= 1;
+      goto no_support;
+      break;
+
+      /* int */
+      /* XXX */
+    case 0xcd:
+      {
+	int ret;
+	if (target_read_memory (i386_record_pc, &tmpu8, 1))
+	  {
+	    printf_unfiltered (_("Record: read memeory 0x%s error.\n"),
+			       paddr_nz (i386_record_pc));
+	    return (-1);
+	  }
+	i386_record_pc++;
+	if (tmpu8 != 0x80
+	    || gdbarch_tdep (gdbarch)->i386_intx80_record == NULL)
+	  {
+	    printf_unfiltered (_
+			       ("Record: record and reverse function don't support instruction int 0x%02x.\n"),
+			       tmpu8);
+	    i386_record_pc -= 2;
+	    goto no_support;
+	  }
+	ret = gdbarch_tdep (gdbarch)->i386_intx80_record ();
+	if (ret)
+	  {
+	    return (ret);
+	  }
+      }
+      break;
+
+      /* into */
+      /* XXX */
+    case 0xce:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction into.\n"));
+      i386_record_pc -= 1;
+      goto no_support;
+      break;
+
+      /* cli */
+    case 0xfa:
+      /* sti */
+    case 0xfb:
+      break;
+
+      /* bound */
+    case 0x62:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction bound.\n"));
+      i386_record_pc -= 1;
+      goto no_support;
+      break;
+
+      /* bswap reg */
+    case 0x0fc8 ... 0x0fcf:
+      if (record_arch_list_add_reg (opcode & 7))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* salc */
+    case 0xd6:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* loopnz */
+    case 0xe0:
+      /* loopz */
+    case 0xe1:
+      /* loop */
+    case 0xe2:
+      /* jecxz */
+    case 0xe3:
+      if (record_arch_list_add_reg (I386_ECX_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* wrmsr */
+    case 0x0f30:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction wrmsr.\n"));
+      i386_record_pc -= 2;
+      goto no_support;
+      break;
+
+      /* rdmsr */
+    case 0x0f32:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction rdmsr.\n"));
+      i386_record_pc -= 2;
+      goto no_support;
+      break;
+
+      /* rdtsc */
+    case 0x0f31:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction rdtsc.\n"));
+      i386_record_pc -= 2;
+      goto no_support;
+      break;
+
+      /* sysenter */
+    case 0x0f34:
+      {
+	int ret;
+	if (gdbarch_tdep (gdbarch)->i386_sysenter_record == NULL)
+	  {
+	    printf_unfiltered (_
+			       ("Record: record and reverse function don't support instruction sysenter.\n"));
+	    i386_record_pc -= 2;
+	    goto no_support;
+	  }
+	ret = gdbarch_tdep (gdbarch)->i386_sysenter_record ();
+	if (ret)
+	  {
+	    return (ret);
+	  }
+      }
+      break;
+
+      /* sysexit */
+    case 0x0f35:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction sysexit.\n"));
+      i386_record_pc -= 2;
+      goto no_support;
+      break;
+
+      /* cpuid */
+    case 0x0fa2:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_ECX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EDX_REGNUM))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EBX_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* hlt */
+    case 0xf4:
+      printf_unfiltered (_
+			 ("Record: record and reverse function don't support instruction hlt.\n"));
+      i386_record_pc -= 1;
+      goto no_support;
+      break;
+
+    case 0x0f00:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      switch (reg)
+	{
+	  /* sldt */
+	case 0:
+	  /* str */
+	case 1:
+	  if (mod == 3)
+	    {
+	      if (record_arch_list_add_reg (rm))
+		{
+		  return (-1);
+		}
+	    }
+	  else
+	    {
+	      ot = OT_WORD;
+	      if (i386_record_lea_modrm ())
+		{
+		  return (-1);
+		}
+	    }
+	  break;
+	  /* lldt */
+	case 2:
+	  /* ltr */
+	case 3:
+	  break;
+	  /* verr */
+	case 4:
+	  /* verw */
+	case 5:
+	  if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	    {
+	      return (-1);
+	    }
+	  break;
+	default:
+	  i386_record_pc -= 3;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	  break;
+	}
+      break;
+
+    case 0x0f01:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      switch (reg)
+	{
+	  /* sgdt */
+	case 0:
+	  {
+	    uint32_t addr;
+
+	    if (mod == 3)
+	      {
+		i386_record_pc -= 3;
+		opcode = opcode << 8 | modrm;
+		goto no_support;
+	      }
+
+	    if (override)
+	      {
+		printf_unfiltered (_
+				   ("Record: cann't get the value of the segment register in address 0x%s. Record ignore this change.\n"),
+				   paddr_nz (read_pc ()));
+	      }
+	    else
+	      {
+		if (i386_record_lea_modrm_addr (&addr))
+		  {
+		    return (-1);
+		  }
+		if (record_arch_list_add_mem (addr, 2))
+		  {
+		    return (-1);
+		  }
+		addr += 2;
+		if (record_arch_list_add_mem (addr, 4))
+		  {
+		    return (-1);
+		  }
+	      }
+	  }
+	  break;
+	case 1:
+	  if (mod == 3)
+	    {
+	      switch (rm)
+		{
+		  /* monitor */
+		case 0:
+		  break;
+		  /* mwait */
+		case 1:
+		  if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+		    {
+		      return (-1);
+		    }
+		  break;
+		default:
+		  i386_record_pc -= 3;
+		  opcode = opcode << 8 | modrm;
+		  goto no_support;
+		  break;
+		}
+	    }
+	  else
+	    {
+	      /* sidt */
+	      if (override)
+		{
+		  printf_unfiltered (_
+				     ("Record: cann't get the value of the segment register in address 0x%s. Record ignore this change.\n"),
+				     paddr_nz (read_pc ()));
+		}
+	      else
+		{
+		  uint32_t addr;
+
+		  if (i386_record_lea_modrm_addr (&addr))
+		    {
+		      return (-1);
+		    }
+		  if (record_arch_list_add_mem (addr, 2))
+		    {
+		      return (-1);
+		    }
+		  addr += 2;
+		  if (record_arch_list_add_mem (addr, 4))
+		    {
+		      return (-1);
+		    }
+		}
+	    }
+	  break;
+	  /* lgdt */
+	case 2:
+	  /* lidt */
+	case 3:
+	  /* invlpg */
+	case 7:
+	default:
+	  if (mod == 3)
+	    {
+	      i386_record_pc -= 3;
+	      opcode = opcode << 8 | modrm;
+	      goto no_support;
+	    }
+	  break;
+	  /* smsw */
+	case 4:
+	  if (mod == 3)
+	    {
+	      if (record_arch_list_add_reg (rm))
+		{
+		  return (-1);
+		}
+	    }
+	  else
+	    {
+	      ot = OT_WORD;
+	      if (i386_record_lea_modrm ())
+		{
+		  return (-1);
+		}
+	    }
+	  break;
+	  /* lmsw */
+	case 6:
+	  break;
+	}
+      break;
+
+      /* invd */
+    case 0x0f08:
+      /* wbinvd */
+    case 0x0f09:
+      break;
+
+      /* arpl */
+    case 0x63:
+      ot = dflag ? OT_LONG : OT_WORD;
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (mod != 3)
+	{
+	  if (i386_record_lea_modrm ())
+	    {
+	      return (-1);
+	    }
+	}
+      else
+	{
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+      /* lar */
+    case 0x0f02:
+      /* lsl */
+    case 0x0f03:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (reg))
+	{
+	  return (-1);
+	}
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+	{
+	  return (-1);
+	}
+      break;
+
+    case 0x0f18:
+      break;
+
+      /* nop (multi byte) */
+    case 0x0f19 ... 0x0f1f:
+      break;
+
+      /* mov reg, crN */
+    case 0x0f20:
+      /* mov crN, reg */
+    case 0x0f22:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if ((modrm & 0xc0) != 0xc0)
+	{
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+      switch (reg)
+	{
+	case 0:
+	case 2:
+	case 3:
+	case 4:
+	case 8:
+	  if (opcode & 2)
+	    {
+	    }
+	  else
+	    {
+	      if (record_arch_list_add_reg (rm))
+		{
+		  return (-1);
+		}
+	    }
+	  break;
+	default:
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	  break;
+	}
+      break;
+
+      /* mov reg, drN */
+    case 0x0f21:
+      /* mov drN, reg */
+    case 0x0f23:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
+      if ((modrm & 0xc0) != 0xc0 || reg == 4 || reg == 5 || reg >= 8)
+	{
+	  i386_record_pc -= 2;
+	  opcode = opcode << 8 | modrm;
+	  goto no_support;
+	}
+      if (opcode & 2)
+	{
+	}
+      else
+	{
+	  if (record_arch_list_add_reg (rm))
+	    {
+	      return (-1);
+	    }
+	}
+      break;
+
+      /* clts */
+    case 0x0f06:
+      break;
+
+      /* MMX/SSE/SSE2/PNI support */
+      /* XXX */
+
+    default:
+      if (opcode > 0xff)
+	{
+	  i386_record_pc -= 2;
+	}
+      else
+	{
+	  i386_record_pc -= 1;
+	}
+      goto no_support;
+      break;
+    }
+
+/* In the future, Maybe still need to deal with need_dasm */
+  if (record_arch_list_add_reg (I386_EIP_REGNUM))
+    {
+      return (-1);
+    }
+  if (record_arch_list_add_end (0))
+    {
+      return (-1);
+    }
+
+  return (0);
+
+no_support:
+  printf_unfiltered (_
+		     ("Record: record and reverse function don't support instruction 0x%02x at address 0x%s.\n"),
+		     (unsigned int) (opcode), paddr_nz (i386_record_pc));
+  return (-1);
+}
 
 static struct gdbarch *
 i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
@@ -2638,6 +5164,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (tdep->mm0_regnum == 0)
     tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
 
+  set_gdbarch_record (gdbarch, i386_record);
+
   return gdbarch;
 }
 
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 227ac66..774dd37 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -106,6 +106,9 @@ struct gdbarch_tdep
   /* ISA-specific data types.  */
   struct type *i386_mmx_type;
   struct type *i386_sse_type;
+
+  int (*i386_intx80_record) (void);
+  int (*i386_sysenter_record) (void);
 };
 
 /* Floating-point registers.  */
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index e223829..caf16f2 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -51,6 +51,7 @@
 #include "exceptions.h"
 #include "cli/cli-decode.h"
 #include "gdbthread.h"
+#include "record.h"
 
 /* Functions exported for general use, in inferior.h: */
 
@@ -194,6 +195,12 @@ CORE_ADDR step_range_end;	/* Exclusive */
 
 struct frame_id step_frame_id;
 
+/* Prev stack frame address of "step_frame_id".
+   When GDB is in the reverse debug mode, it is used to make sure if inferior return to
+   the prev function. */
+
+struct frame_id step_prev_frame_id;
+
 enum step_over_calls_kind step_over_calls;
 
 /* If stepping, nonzero means step count is > 1
@@ -458,10 +465,20 @@ kill_if_already_running (int from_tty)
 	 restart it.  */
       target_require_runnable ();
 
-      if (from_tty
-	  && !query ("The program being debugged has been started already.\n\
+      if (RECORD_IS_USED)
+        {
+          if (from_tty
+	      && !query ("The program being debugged and target record have been started already.\n\
+Stop target record and start the program being debugged from the beginning? "))
+	    error (_("Program not restarted."));
+        }
+      else
+        {
+          if (from_tty
+	      && !query ("The program being debugged has been started already.\n\
 Start it from the beginning? "))
-	error (_("Program not restarted."));
+	    error (_("Program not restarted."));
+        }
       target_kill ();
       no_shared_libraries (NULL, from_tty);
       init_wait_for_inferior ();
@@ -750,6 +767,19 @@ step_1 (int skip_subroutines, int single_inst, char *count_string)
 	    error (_("No current frame"));
 	  step_frame_id = get_frame_id (frame);
 
+	  if (target_get_execution_direction () == EXEC_REVERSE)
+	    {
+	      frame = get_prev_frame (frame);
+	      if (frame)
+	        {
+		  step_prev_frame_id = get_frame_id (frame);
+	        }
+	      else
+	        {
+		  step_prev_frame_id = null_frame_id;
+	        }
+	    }
+
 	  if (!single_inst)
 	    {
 	      find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
@@ -859,6 +889,19 @@ step_once (int skip_subroutines, int single_inst, int count, int thread)
 	error (_("No current frame"));
       step_frame_id = get_frame_id (frame);
 
+      if (target_get_execution_direction () == EXEC_REVERSE)
+        {
+          frame = get_prev_frame (frame);
+          if (frame)
+            {
+              step_prev_frame_id = get_frame_id (frame);
+            }
+          else
+            {
+              step_prev_frame_id = null_frame_id;
+            }
+        }
+
       if (!single_inst)
 	{
 	  find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
@@ -1133,6 +1176,19 @@ until_next_command (int from_tty)
   step_over_calls = STEP_OVER_ALL;
   step_frame_id = get_frame_id (frame);
 
+  if (target_get_execution_direction () == EXEC_REVERSE)
+    {
+      frame = get_prev_frame (frame);
+      if (frame)
+        {
+          step_prev_frame_id = get_frame_id (frame);
+        }
+      else
+        {
+	  step_prev_frame_id = null_frame_id;
+        }
+    }
+
   step_multi = 0;		/* Only one call to proceed */
 
   proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
diff --git a/gdb/inferior.h b/gdb/inferior.h
index 1dd152a..a57e678 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -314,6 +314,12 @@ extern CORE_ADDR step_range_end;	/* Exclusive */
 
 extern struct frame_id step_frame_id;
 
+/* Prev stack frame address of "step_frame_id".
+   When GDB is in the reverse debug mode, it is used to make sure if inferior return to
+   the prev function. */
+
+extern struct frame_id step_prev_frame_id;
+
 /* 1 means step over all subroutine calls.
    -1 means step over calls to undebuggable functions.  */
 
diff --git a/gdb/inflow.c b/gdb/inflow.c
index 6a77531..c0996a9 100644
--- a/gdb/inflow.c
+++ b/gdb/inflow.c
@@ -34,6 +34,8 @@
 
 #include "inflow.h"
 
+#include "record.h"
+
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
@@ -594,8 +596,16 @@ kill_command (char *arg, int from_tty)
 
   if (ptid_equal (inferior_ptid, null_ptid))
     error (_("The program is not being run."));
-  if (!query ("Kill the program being debugged? "))
-    error (_("Not confirmed."));
+  if (RECORD_IS_USED)
+    {
+      if (!query ("Stop the record target and kill the program being debugged? "))
+        error (_("Not confirmed."));
+    }
+  else
+    {
+      if (!query ("Kill the program being debugged? "))
+        error (_("Not confirmed."));
+    }
   target_kill ();
 
   init_thread_list ();		/* Destroy thread info */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index e7d1dec..569ec1b 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -49,6 +49,14 @@
 #include "gdb_assert.h"
 #include "mi/mi-common.h"
 
+#include "record.h"
+
+/* When the record function want inferior step before call function
+   "keep_going", "reverse_resume_need_step" will be set to 1. It will be set
+   back to 0 in the begin of function "handle_inferior_event" because it just
+   be accessed by the sub-functions of "handle_inferior_event". */
+static int reverse_resume_need_step = 0;
+
 /* Prototypes for local functions */
 
 static void signals_info (char *, int);
@@ -320,8 +328,7 @@ show_follow_fork_mode_string (struct ui_file *file, int from_tty,
 			      struct cmd_list_element *c, const char *value)
 {
   fprintf_filtered (file, _("\
-Debugger response to a program call of fork or vfork is \"%s\".\n"),
-		    value);
+Debugger response to a program call of fork or vfork is \"%s\".\n"), value);
 }
 
 
@@ -409,8 +416,7 @@ follow_exec (int pid, char *execd_pathname)
   if (gdb_sysroot && *gdb_sysroot)
     {
       char *name = alloca (strlen (gdb_sysroot)
-			    + strlen (execd_pathname)
-			    + 1);
+			   + strlen (execd_pathname) + 1);
       strcpy (name, gdb_sysroot);
       strcat (name, execd_pathname);
       execd_pathname = name;
@@ -559,7 +565,7 @@ static ptid_t deferred_step_ptid;
 /* If this is not null_ptid, this is the thread carrying out a
    displaced single-step.  This thread's state will require fixing up
    once it has completed its step.  */
-static ptid_t displaced_step_ptid;
+ptid_t displaced_step_ptid;
 
 struct displaced_step_request
 {
@@ -578,7 +584,7 @@ static struct gdbarch *displaced_step_gdbarch;
 static struct displaced_step_closure *displaced_step_closure;
 
 /* The address of the original instruction, and the copy we made.  */
-static CORE_ADDR displaced_step_original, displaced_step_copy;
+CORE_ADDR displaced_step_original, displaced_step_copy;
 
 /* Saved contents of copy area.  */
 static gdb_byte *displaced_step_saved_copy;
@@ -593,8 +599,7 @@ show_can_use_displaced_stepping (struct ui_file *file, int from_tty,
 				 const char *value)
 {
   fprintf_filtered (file, _("\
-Debugger's willingness to use displaced stepping to step over "
-"breakpoints is %s.\n"), value);
+Debugger's willingness to use displaced stepping to step over " "breakpoints is %s.\n"), value);
 }
 
 /* Return non-zero if displaced stepping is enabled, and can be used
@@ -603,7 +608,8 @@ static int
 use_displaced_stepping (struct gdbarch *gdbarch)
 {
   return (can_use_displaced_stepping
-	  && gdbarch_displaced_step_copy_insn_p (gdbarch));
+	  && gdbarch_displaced_step_copy_insn_p (gdbarch)
+	  && !RECORD_IS_REPLAY);
 }
 
 /* Clean out any stray displaced stepping state.  */
@@ -616,7 +622,7 @@ displaced_step_clear (void)
   if (displaced_step_closure)
     {
       gdbarch_displaced_step_free_closure (displaced_step_gdbarch,
-                                           displaced_step_closure);
+					   displaced_step_closure);
       displaced_step_closure = NULL;
     }
 }
@@ -632,8 +638,7 @@ cleanup_displaced_step_closure (void *ptr)
 /* Dump LEN bytes at BUF in hex to FILE, followed by a newline.  */
 void
 displaced_step_dump_bytes (struct ui_file *file,
-                           const gdb_byte *buf,
-                           size_t len)
+			   const gdb_byte * buf, size_t len)
 {
   int i;
 
@@ -676,7 +681,7 @@ displaced_step_prepare (ptid_t ptid)
   if (!ptid_equal (displaced_step_ptid, null_ptid))
     {
       /* Already waiting for a displaced step to finish.  Defer this
-	 request and place in queue.  */
+         request and place in queue.  */
       struct displaced_step_request *req, *new_req;
 
       if (debug_displaced)
@@ -691,8 +696,7 @@ displaced_step_prepare (ptid_t ptid)
       if (displaced_step_request_queue)
 	{
 	  for (req = displaced_step_request_queue;
-	       req && req->next;
-	       req = req->next)
+	       req && req->next; req = req->next)
 	    ;
 	  req->next = new_req;
 	}
@@ -719,7 +723,7 @@ displaced_step_prepare (ptid_t ptid)
   /* Save the original contents of the copy area.  */
   displaced_step_saved_copy = xmalloc (len);
   old_cleanups = make_cleanup (free_current_contents,
-                               &displaced_step_saved_copy);
+			       &displaced_step_saved_copy);
   read_memory (copy, displaced_step_saved_copy, len);
   if (debug_displaced)
     {
@@ -729,7 +733,7 @@ displaced_step_prepare (ptid_t ptid)
     };
 
   closure = gdbarch_displaced_step_copy_insn (gdbarch,
-                                              original, copy, regcache);
+					      original, copy, regcache);
 
   /* We don't support the fully-simulated case at present.  */
   gdb_assert (closure);
@@ -743,7 +747,7 @@ displaced_step_prepare (ptid_t ptid)
 
   if (debug_displaced)
     fprintf_unfiltered (gdb_stdlog, "displaced: displaced pc to 0x%s\n",
-                        paddr_nz (copy));
+			paddr_nz (copy));
 
   /* Save the information we need to fix things up if the step
      succeeds.  */
@@ -762,7 +766,8 @@ displaced_step_clear_cleanup (void *ignore)
 }
 
 static void
-write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+write_memory_ptid (ptid_t ptid, CORE_ADDR memaddr, const gdb_byte * myaddr,
+		   int len)
 {
   struct cleanup *ptid_cleanup = save_inferior_ptid ();
   inferior_ptid = ptid;
@@ -777,7 +782,7 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
 
   /* Was this event for the pid we displaced?  */
   if (ptid_equal (displaced_step_ptid, null_ptid)
-      || ! ptid_equal (displaced_step_ptid, event_ptid))
+      || !ptid_equal (displaced_step_ptid, event_ptid))
     return;
 
   old_cleanups = make_cleanup (displaced_step_clear_cleanup, 0);
@@ -789,7 +794,7 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
 		       displaced_step_saved_copy, len);
     if (debug_displaced)
       fprintf_unfiltered (gdb_stdlog, "displaced: restored 0x%s\n",
-                          paddr_nz (displaced_step_copy));
+			  paddr_nz (displaced_step_copy));
   }
 
   /* Did the instruction complete successfully?  */
@@ -797,10 +802,11 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
     {
       /* Fix up the resulting state.  */
       gdbarch_displaced_step_fixup (displaced_step_gdbarch,
-                                    displaced_step_closure,
-                                    displaced_step_original,
-                                    displaced_step_copy,
-                                    get_thread_regcache (displaced_step_ptid));
+				    displaced_step_closure,
+				    displaced_step_original,
+				    displaced_step_copy,
+				    get_thread_regcache
+				    (displaced_step_ptid));
     }
   else
     {
@@ -837,8 +843,8 @@ displaced_step_fixup (ptid_t event_ptid, enum target_signal signal)
       target_resume (ptid, 1, TARGET_SIGNAL_0);
     }
 }
-
 
+
 /* Resuming.  */
 
 /* Things to clean up if we QUIT out of resume ().  */
@@ -863,8 +869,7 @@ show_scheduler_mode (struct ui_file *file, int from_tty,
 		     struct cmd_list_element *c, const char *value)
 {
   fprintf_filtered (file, _("\
-Mode for locking scheduler during execution is \"%s\".\n"),
-		    value);
+Mode for locking scheduler during execution is \"%s\".\n"), value);
 }
 
 static void
@@ -898,8 +903,8 @@ resume (int step, enum target_signal sig)
 
   if (debug_infrun)
     fprintf_unfiltered (gdb_stdlog,
-                        "infrun: resume (step=%d, signal=%d), "
-                        "stepping_over_breakpoint=%d\n",
+			"infrun: resume (step=%d, signal=%d), "
+			"stepping_over_breakpoint=%d\n",
 			step, sig, stepping_over_breakpoint);
 
   /* Some targets (e.g. Solaris x86) have a kernel bug when stepping
@@ -937,8 +942,7 @@ a command like `return' or `jump' to continue execution."));
      comments in the handle_inferior event for dealing with 'random
      signals' explain what we do instead.  */
   if (use_displaced_stepping (gdbarch)
-      && stepping_over_breakpoint
-      && sig == TARGET_SIGNAL_0)
+      && stepping_over_breakpoint && sig == TARGET_SIGNAL_0)
     {
       if (!displaced_step_prepare (inferior_ptid))
 	/* Got placed in displaced stepping queue.  Will be resumed
@@ -951,15 +955,15 @@ a command like `return' or `jump' to continue execution."));
     {
       /* Do it the hard way, w/temp breakpoints */
       if (gdbarch_software_single_step (gdbarch, get_current_frame ()))
-        {
-          /* ...and don't ask hardware to do it.  */
-          step = 0;
-          /* and do not pull these breakpoints until after a `wait' in
-          `wait_for_inferior' */
-          singlestep_breakpoints_inserted_p = 1;
-          singlestep_ptid = inferior_ptid;
-          singlestep_pc = pc;
-        }
+	{
+	  /* ...and don't ask hardware to do it.  */
+	  step = 0;
+	  /* and do not pull these breakpoints until after a `wait' in
+	     `wait_for_inferior' */
+	  singlestep_breakpoints_inserted_p = 1;
+	  singlestep_ptid = inferior_ptid;
+	  singlestep_pc = pc;
+	}
     }
 
   /* If there were any forks/vforks/execs that were caught and are
@@ -992,8 +996,8 @@ a command like `return' or `jump' to continue execution."));
       resume_ptid = RESUME_ALL;	/* Default */
 
       /* If STEP is set, it's a request to use hardware stepping
-	 facilities.  But in that case, we should never
-	 use singlestep breakpoint.  */
+         facilities.  But in that case, we should never
+         use singlestep breakpoint.  */
       gdb_assert (!(singlestep_breakpoints_inserted_p && step));
 
       if (singlestep_breakpoints_inserted_p
@@ -1047,18 +1051,18 @@ a command like `return' or `jump' to continue execution."));
 	}
 
       if (debug_displaced
-          && use_displaced_stepping (gdbarch)
-          && stepping_over_breakpoint)
-        {
-	  struct regcache *resume_regcache = get_thread_regcache (resume_ptid);
-          CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
-          gdb_byte buf[4];
-
-          fprintf_unfiltered (gdb_stdlog, "displaced: run 0x%s: ",
-                              paddr_nz (actual_pc));
-          read_memory (actual_pc, buf, sizeof (buf));
-          displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
-        }
+	  && use_displaced_stepping (gdbarch) && stepping_over_breakpoint)
+	{
+	  struct regcache *resume_regcache =
+	    get_thread_regcache (resume_ptid);
+	  CORE_ADDR actual_pc = regcache_read_pc (resume_regcache);
+	  gdb_byte buf[4];
+
+	  fprintf_unfiltered (gdb_stdlog, "displaced: run 0x%s: ",
+			      paddr_nz (actual_pc));
+	  read_memory (actual_pc, buf, sizeof (buf));
+	  displaced_step_dump_bytes (gdb_stdlog, buf, sizeof (buf));
+	}
 
       target_resume (resume_ptid, step, sig);
     }
@@ -1167,7 +1171,10 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
   if (step < 0)
     stop_after_trap = 1;
 
-  if (addr == (CORE_ADDR) -1)
+  if (RECORD_IS_USED)
+    record_not_record_set ();
+
+  if (addr == (CORE_ADDR) - 1)
     {
       if (pc == stop_pc && breakpoint_here_p (pc))
 	/* There is a breakpoint at the address we will resume at,
@@ -1210,10 +1217,10 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
     {
       stepping_over_breakpoint = 1;
       /* If displaced stepping is enabled, we can step over the
-	 breakpoint without hitting it, so leave all breakpoints
-	 inserted.  Otherwise we need to disable all breakpoints, step
-	 one instruction, and then re-add them when that step is
-	 finished.  */
+         breakpoint without hitting it, so leave all breakpoints
+         inserted.  Otherwise we need to disable all breakpoints, step
+         one instruction, and then re-add them when that step is
+         finished.  */
       if (!use_displaced_stepping (gdbarch))
 	remove_breakpoints ();
     }
@@ -1221,7 +1228,7 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
   /* We can insert breakpoints if we're not trying to step over one,
      or if we are stepping over one but we're using displaced stepping
      to do so.  */
-  if (! stepping_over_breakpoint || use_displaced_stepping (gdbarch))
+  if (!stepping_over_breakpoint || use_displaced_stepping (gdbarch))
     insert_breakpoints ();
 
   if (siggnal != TARGET_SIGNAL_DEFAULT)
@@ -1335,8 +1342,8 @@ init_wait_for_inferior (void)
 
   displaced_step_clear ();
 }
-
 
+
 /* This enum encodes possible reasons for doing a target_wait, so that
    wfi can call target_wait in one place.  (Ultimately the call will be
    moved out of the infinite loop entirely.) */
@@ -1400,9 +1407,11 @@ void init_execution_control_state (struct execution_control_state *ecs);
 void handle_inferior_event (struct execution_control_state *ecs);
 
 static void step_into_function (struct execution_control_state *ecs);
-static void insert_step_resume_breakpoint_at_frame (struct frame_info *step_frame);
+static void insert_step_resume_breakpoint_at_frame (struct frame_info
+						    *step_frame);
 static void insert_step_resume_breakpoint_at_caller (struct frame_info *);
-static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal,
+static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line
+						  sr_sal,
 						  struct frame_id sr_id);
 static void insert_longjmp_resume_breakpoint (CORE_ADDR);
 
@@ -1467,11 +1476,11 @@ wait_for_inferior (int treat_exec_as_sigtrap)
 	ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
 
       if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
-        {
-          xfree (ecs->ws.value.execd_pathname);
-          ecs->ws.kind = TARGET_WAITKIND_STOPPED;
-          ecs->ws.value.sig = TARGET_SIGNAL_TRAP;
-        }
+	{
+	  xfree (ecs->ws.value.execd_pathname);
+	  ecs->ws.kind = TARGET_WAITKIND_STOPPED;
+	  ecs->ws.value.sig = TARGET_SIGNAL_TRAP;
+	}
 
       /* Now figure out what to do with the result of the result.  */
       handle_inferior_event (ecs);
@@ -1566,7 +1575,7 @@ init_execution_control_state (struct execution_control_state *ecs)
    after target_wait()/deprecated_target_wait_hook().  */
 
 void
-get_last_target_status (ptid_t *ptidp, struct target_waitstatus *status)
+get_last_target_status (ptid_t * ptidp, struct target_waitstatus *status)
 {
   *ptidp = target_last_wait_ptid;
   *status = target_last_waitstatus;
@@ -1665,34 +1674,33 @@ adjust_pc_after_break (struct execution_control_state *ecs)
   /* Find the location where (if we've hit a breakpoint) the
      breakpoint would be.  */
   breakpoint_pc = regcache_read_pc (regcache)
-		  - gdbarch_decr_pc_after_break (gdbarch);
+    - gdbarch_decr_pc_after_break (gdbarch);
 
   /* Check whether there actually is a software breakpoint inserted
      at that location.  */
   if (software_breakpoint_inserted_here_p (breakpoint_pc))
     {
       /* When using hardware single-step, a SIGTRAP is reported for both
-	 a completed single-step and a software breakpoint.  Need to
-	 differentiate between the two, as the latter needs adjusting
-	 but the former does not.
+         a completed single-step and a software breakpoint.  Need to
+         differentiate between the two, as the latter needs adjusting
+         but the former does not.
 
-	 The SIGTRAP can be due to a completed hardware single-step only if 
-	  - we didn't insert software single-step breakpoints
-	  - the thread to be examined is still the current thread
-	  - this thread is currently being stepped
+         The SIGTRAP can be due to a completed hardware single-step only if 
+         - we didn't insert software single-step breakpoints
+         - the thread to be examined is still the current thread
+         - this thread is currently being stepped
 
-	 If any of these events did not occur, we must have stopped due
-	 to hitting a software breakpoint, and have to back up to the
-	 breakpoint address.
+         If any of these events did not occur, we must have stopped due
+         to hitting a software breakpoint, and have to back up to the
+         breakpoint address.
 
-	 As a special case, we could have hardware single-stepped a
-	 software breakpoint.  In this case (prev_pc == breakpoint_pc),
-	 we also need to back up to the breakpoint address.  */
+         As a special case, we could have hardware single-stepped a
+         software breakpoint.  In this case (prev_pc == breakpoint_pc),
+         we also need to back up to the breakpoint address.  */
 
       if (singlestep_breakpoints_inserted_p
 	  || !ptid_equal (ecs->ptid, inferior_ptid)
-	  || !currently_stepping (ecs)
-	  || prev_pc == breakpoint_pc)
+	  || !currently_stepping (ecs) || prev_pc == breakpoint_pc)
 	regcache_write_pc (regcache, breakpoint_pc);
     }
 }
@@ -1708,6 +1716,9 @@ handle_inferior_event (struct execution_control_state *ecs)
   int stopped_by_watchpoint;
   int stepped_after_stopped_by_watchpoint = 0;
 
+  /* Reset reverse_resume_need_step to 0. */
+  reverse_resume_need_step = 0;
+
   /* Cache the last pid/waitstatus. */
   target_last_wait_ptid = ecs->ptid;
   target_last_waitstatus = *ecs->wp;
@@ -1721,27 +1732,26 @@ handle_inferior_event (struct execution_control_state *ecs)
     {
     case infwait_thread_hop_state:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: infwait_thread_hop_state\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: infwait_thread_hop_state\n");
       /* Cancel the waiton_ptid. */
       ecs->waiton_ptid = pid_to_ptid (-1);
       break;
 
     case infwait_normal_state:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: infwait_normal_state\n");
       break;
 
     case infwait_step_watch_state:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog,
-			    "infrun: infwait_step_watch_state\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: infwait_step_watch_state\n");
 
       stepped_after_stopped_by_watchpoint = 1;
       break;
 
     case infwait_nonstep_watch_state:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog,
+	fprintf_unfiltered (gdb_stdlog,
 			    "infrun: infwait_nonstep_watch_state\n");
       insert_breakpoints ();
 
@@ -1772,7 +1782,7 @@ handle_inferior_event (struct execution_control_state *ecs)
     {
     case TARGET_WAITKIND_LOADED:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_LOADED\n");
       /* Ignore gracefully during startup of the inferior, as it might
          be the shell which has just loaded some objects, otherwise
          add the symbols for the newly loaded objects.  Also ignore at
@@ -1823,9 +1833,9 @@ handle_inferior_event (struct execution_control_state *ecs)
 	}
 
       /* If we are skipping through a shell, or through shared library
-	 loading that we aren't interested in, resume the program.  If
-	 we're running the program normally, also resume.  But stop if
-	 we're attaching or setting up a remote connection.  */
+         loading that we aren't interested in, resume the program.  If
+         we're running the program normally, also resume.  But stop if
+         we're attaching or setting up a remote connection.  */
       if (stop_soon == STOP_QUIETLY || stop_soon == NO_STOP_QUIETLY)
 	{
 	  /* Loading of shared libraries might have changed breakpoint
@@ -1842,14 +1852,14 @@ handle_inferior_event (struct execution_control_state *ecs)
 
     case TARGET_WAITKIND_SPURIOUS:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SPURIOUS\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SPURIOUS\n");
       resume (0, TARGET_SIGNAL_0);
       prepare_to_wait (ecs);
       return;
 
     case TARGET_WAITKIND_EXITED:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXITED\n");
       target_terminal_ours ();	/* Must do this before mourn anyway */
       print_stop_reason (EXITED, ecs->ws.value.integer);
 
@@ -1867,7 +1877,8 @@ handle_inferior_event (struct execution_control_state *ecs)
 
     case TARGET_WAITKIND_SIGNALLED:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SIGNALLED\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: TARGET_WAITKIND_SIGNALLED\n");
       stop_print_frame = 0;
       stop_signal = ecs->ws.value.sig;
       target_terminal_ours ();	/* Must do this before mourn anyway */
@@ -1889,7 +1900,7 @@ handle_inferior_event (struct execution_control_state *ecs)
     case TARGET_WAITKIND_FORKED:
     case TARGET_WAITKIND_VFORKED:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_FORKED\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_FORKED\n");
       stop_signal = TARGET_SIGNAL_TRAP;
       pending_follow.kind = ecs->ws.kind;
 
@@ -1919,7 +1930,7 @@ handle_inferior_event (struct execution_control_state *ecs)
 
     case TARGET_WAITKIND_EXECD:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_EXECD\n");
       stop_signal = TARGET_SIGNAL_TRAP;
 
       pending_follow.execd_pathname =
@@ -1959,7 +1970,8 @@ handle_inferior_event (struct execution_control_state *ecs)
          that's in a syscall.  It's frequently a losing proposition.  */
     case TARGET_WAITKIND_SYSCALL_ENTRY:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
       resume (0, TARGET_SIGNAL_0);
       prepare_to_wait (ecs);
       return;
@@ -1971,14 +1983,15 @@ handle_inferior_event (struct execution_control_state *ecs)
          into user code.)  */
     case TARGET_WAITKIND_SYSCALL_RETURN:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
       target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
       prepare_to_wait (ecs);
       return;
 
     case TARGET_WAITKIND_STOPPED:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_STOPPED\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_STOPPED\n");
       stop_signal = ecs->ws.value.sig;
       break;
 
@@ -1999,7 +2012,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          reported multiple times without an intervening resume.  */
     case TARGET_WAITKIND_IGNORE:
       if (debug_infrun)
-        fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_IGNORE\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_IGNORE\n");
       prepare_to_wait (ecs);
       return;
     }
@@ -2028,19 +2041,19 @@ handle_inferior_event (struct execution_control_state *ecs)
   if (debug_infrun)
     {
       fprintf_unfiltered (gdb_stdlog, "infrun: stop_pc = 0x%s\n",
-                          paddr_nz (stop_pc));
+			  paddr_nz (stop_pc));
       if (STOPPED_BY_WATCHPOINT (&ecs->ws))
 	{
-          CORE_ADDR addr;
+	  CORE_ADDR addr;
 	  fprintf_unfiltered (gdb_stdlog, "infrun: stopped by watchpoint\n");
 
-          if (target_stopped_data_address (&current_target, &addr))
-            fprintf_unfiltered (gdb_stdlog,
-                                "infrun: stopped data address = 0x%s\n",
-                                paddr_nz (addr));
-          else
-            fprintf_unfiltered (gdb_stdlog,
-                                "infrun: (no data address available)\n");
+	  if (target_stopped_data_address (&current_target, &addr))
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: stopped data address = 0x%s\n",
+				paddr_nz (addr));
+	  else
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: (no data address available)\n");
 	}
     }
 
@@ -2058,7 +2071,8 @@ handle_inferior_event (struct execution_control_state *ecs)
       if (stop_signal == TARGET_SIGNAL_TRAP)
 	{
 	  if (debug_infrun)
-	    fprintf_unfiltered (gdb_stdlog, "infrun: stepping_past_singlestep_breakpoint\n");
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: stepping_past_singlestep_breakpoint\n");
 	  /* Pull the single step breakpoints out of the target.  */
 	  remove_single_step_breakpoints ();
 	  singlestep_breakpoints_inserted_p = 0;
@@ -2081,7 +2095,7 @@ handle_inferior_event (struct execution_control_state *ecs)
   if (!ptid_equal (deferred_step_ptid, null_ptid))
     {
       /* If we stopped for some other reason than single-stepping, ignore
-	 the fact that we were supposed to switch back.  */
+         the fact that we were supposed to switch back.  */
       if (stop_signal == TARGET_SIGNAL_TRAP)
 	{
 	  if (debug_infrun)
@@ -2146,49 +2160,50 @@ handle_inferior_event (struct execution_control_state *ecs)
 	      && in_thread_list (singlestep_ptid))
 	    {
 	      /* If the PC of the thread we were trying to single-step
-		 has changed, discard this event (which we were going
-		 to ignore anyway), and pretend we saw that thread
-		 trap.  This prevents us continuously moving the
-		 single-step breakpoint forward, one instruction at a
-		 time.  If the PC has changed, then the thread we were
-		 trying to single-step has trapped or been signalled,
-		 but the event has not been reported to GDB yet.
-
-		 There might be some cases where this loses signal
-		 information, if a signal has arrived at exactly the
-		 same time that the PC changed, but this is the best
-		 we can do with the information available.  Perhaps we
-		 should arrange to report all events for all threads
-		 when they stop, or to re-poll the remote looking for
-		 this particular thread (i.e. temporarily enable
-		 schedlock).  */
-
-	     CORE_ADDR new_singlestep_pc
-	       = regcache_read_pc (get_thread_regcache (singlestep_ptid));
-
-	     if (new_singlestep_pc != singlestep_pc)
-	       {
-		 if (debug_infrun)
-		   fprintf_unfiltered (gdb_stdlog, "infrun: unexpected thread,"
-				       " but expected thread advanced also\n");
-
-		 /* The current context still belongs to
-		    singlestep_ptid.  Don't swap here, since that's
-		    the context we want to use.  Just fudge our
-		    state and continue.  */
-                 ecs->ptid = singlestep_ptid;
-                 stop_pc = new_singlestep_pc;
-               }
-             else
-	       {
-		 if (debug_infrun)
-		   fprintf_unfiltered (gdb_stdlog,
-				       "infrun: unexpected thread\n");
-
-		 thread_hop_needed = 1;
-		 stepping_past_singlestep_breakpoint = 1;
-		 saved_singlestep_ptid = singlestep_ptid;
-	       }
+	         has changed, discard this event (which we were going
+	         to ignore anyway), and pretend we saw that thread
+	         trap.  This prevents us continuously moving the
+	         single-step breakpoint forward, one instruction at a
+	         time.  If the PC has changed, then the thread we were
+	         trying to single-step has trapped or been signalled,
+	         but the event has not been reported to GDB yet.
+
+	         There might be some cases where this loses signal
+	         information, if a signal has arrived at exactly the
+	         same time that the PC changed, but this is the best
+	         we can do with the information available.  Perhaps we
+	         should arrange to report all events for all threads
+	         when they stop, or to re-poll the remote looking for
+	         this particular thread (i.e. temporarily enable
+	         schedlock).  */
+
+	      CORE_ADDR new_singlestep_pc
+		= regcache_read_pc (get_thread_regcache (singlestep_ptid));
+
+	      if (new_singlestep_pc != singlestep_pc)
+		{
+		  if (debug_infrun)
+		    fprintf_unfiltered (gdb_stdlog,
+					"infrun: unexpected thread,"
+					" but expected thread advanced also\n");
+
+		  /* The current context still belongs to
+		     singlestep_ptid.  Don't swap here, since that's
+		     the context we want to use.  Just fudge our
+		     state and continue.  */
+		  ecs->ptid = singlestep_ptid;
+		  stop_pc = new_singlestep_pc;
+		}
+	      else
+		{
+		  if (debug_infrun)
+		    fprintf_unfiltered (gdb_stdlog,
+					"infrun: unexpected thread\n");
+
+		  thread_hop_needed = 1;
+		  stepping_past_singlestep_breakpoint = 1;
+		  saved_singlestep_ptid = singlestep_ptid;
+		}
 	    }
 	}
 
@@ -2287,17 +2302,17 @@ handle_inferior_event (struct execution_control_state *ecs)
          In order to make watchpoints work `right', we really need
          to complete the memory write, and then evaluate the
          watchpoint expression.  We do this by single-stepping the
-	 target.
+         target.
+
+         It may not be necessary to disable the watchpoint to stop over
+         it.  For example, the PA can (with some kernel cooperation)
+         single step over a watchpoint without disabling the watchpoint.
 
-	 It may not be necessary to disable the watchpoint to stop over
-	 it.  For example, the PA can (with some kernel cooperation)
-	 single step over a watchpoint without disabling the watchpoint.
+         It is far more common to need to disable a watchpoint to step
+         the inferior over it.  If we have non-steppable watchpoints,
+         we must disable the current watchpoint; it's simplest to
+         disable all watchpoints and breakpoints.  */
 
-	 It is far more common to need to disable a watchpoint to step
-	 the inferior over it.  If we have non-steppable watchpoints,
-	 we must disable the current watchpoint; it's simplest to
-	 disable all watchpoints and breakpoints.  */
-	 
       if (!HAVE_STEPPABLE_WATCHPOINT)
 	remove_breakpoints ();
       registers_changed ();
@@ -2333,10 +2348,10 @@ handle_inferior_event (struct execution_control_state *ecs)
       && currently_stepping (ecs))
     {
       /* We're trying to step off a breakpoint.  Turns out that we're
-	 also on an instruction that needs to be stepped multiple
-	 times before it's been fully executing. E.g., architectures
-	 with a delay slot.  It needs to be stepped twice, once for
-	 the instruction and once for the delay slot.  */
+         also on an instruction that needs to be stepped multiple
+         times before it's been fully executing. E.g., architectures
+         with a delay slot.  It needs to be stepped twice, once for
+         the instruction and once for the delay slot.  */
       int step_through_delay
 	= gdbarch_single_step_through_delay (current_gdbarch,
 					     get_current_frame ());
@@ -2346,9 +2361,9 @@ handle_inferior_event (struct execution_control_state *ecs)
 	{
 	  /* The user issued a continue when stopped at a breakpoint.
 	     Set up for another trap and get out of here.  */
-         ecs->stepping_over_breakpoint = 1;
-         keep_going (ecs);
-         return;
+	  ecs->stepping_over_breakpoint = 1;
+	  keep_going (ecs);
+	  return;
 	}
       else if (step_through_delay)
 	{
@@ -2385,8 +2400,8 @@ handle_inferior_event (struct execution_control_state *ecs)
      breakpoint is always inserted at the original instruction;
      non-standard signals can't be explained by the breakpoint.  */
   if (stop_signal == TARGET_SIGNAL_TRAP
-      || (! stepping_over_breakpoint
-          && breakpoint_inserted_here_p (stop_pc)
+      || (!stepping_over_breakpoint
+	  && breakpoint_inserted_here_p (stop_pc)
 	  && (stop_signal == TARGET_SIGNAL_ILL
 	      || stop_signal == TARGET_SIGNAL_SEGV
 	      || stop_signal == TARGET_SIGNAL_EMT))
@@ -2395,7 +2410,7 @@ handle_inferior_event (struct execution_control_state *ecs)
     {
       if (stop_signal == TARGET_SIGNAL_TRAP && stop_after_trap)
 	{
-          if (debug_infrun)
+	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog, "infrun: stopped\n");
 	  stop_print_frame = 0;
 	  stop_stepping (ecs);
@@ -2406,7 +2421,7 @@ handle_inferior_event (struct execution_control_state *ecs)
          shared libraries hook functions.  */
       if (stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_REMOTE)
 	{
-          if (debug_infrun)
+	  if (debug_infrun)
 	    fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
 	  stop_stepping (ecs);
 	  return;
@@ -2416,8 +2431,8 @@ handle_inferior_event (struct execution_control_state *ecs)
          the stop_signal here, because some kernels don't ignore a
          SIGSTOP in a subsequent ptrace(PTRACE_CONT,SIGSTOP) call.
          See more comments in inferior.h.  On the other hand, if we
-	 get a non-SIGSTOP, report it to the user - assume the backend
-	 will handle the SIGSTOP if it should show up later.  */
+         get a non-SIGSTOP, report it to the user - assume the backend
+         will handle the SIGSTOP if it should show up later.  */
       if (stop_soon == STOP_QUIETLY_NO_SIGSTOP
 	  && stop_signal == TARGET_SIGNAL_STOP)
 	{
@@ -2428,9 +2443,9 @@ handle_inferior_event (struct execution_control_state *ecs)
 
       /* See if there is a breakpoint at the current PC.  */
       stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
-      
+
       /* Following in case break condition called a
-	 function.  */
+         function.  */
       stop_print_frame = 1;
 
       /* NOTE: cagney/2003-03-29: These two checks for a random signal
@@ -2457,7 +2472,9 @@ handle_inferior_event (struct execution_control_state *ecs)
 	ecs->random_signal
 	  = !(bpstat_explains_signal (stop_bpstat)
 	      || stepping_over_breakpoint
-	      || (step_range_end && step_resume_breakpoint == NULL));
+	      || (step_range_end && step_resume_breakpoint == NULL)
+	      || (target_get_execution_direction () == EXEC_REVERSE)
+	      || RECORD_IS_USED);
       else
 	{
 	  ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
@@ -2483,7 +2500,8 @@ process_event_stop_test:
       int printed = 0;
 
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n", stop_signal);
+	fprintf_unfiltered (gdb_stdlog, "infrun: random signal %d\n",
+			    stop_signal);
 
       stopped_by_random_signal = 1;
 
@@ -2508,8 +2526,7 @@ process_event_stop_test:
 	stop_signal = TARGET_SIGNAL_0;
 
       if (prev_pc == read_pc ()
-	  && stepping_over_breakpoint
-	  && step_resume_breakpoint == NULL)
+	  && stepping_over_breakpoint && step_resume_breakpoint == NULL)
 	{
 	  /* We were just starting a new sequence, attempting to
 	     single-step off of a breakpoint and expecting a SIGTRAP.
@@ -2521,10 +2538,10 @@ process_event_stop_test:
 	     code paths as single-step - set a breakpoint at the
 	     signal return address and then, once hit, step off that
 	     breakpoint.  */
-          if (debug_infrun)
-            fprintf_unfiltered (gdb_stdlog,
-                                "infrun: signal arrived while stepping over "
-                                "breakpoint\n");
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: signal arrived while stepping over "
+				"breakpoint\n");
 
 	  insert_step_resume_breakpoint_at_frame (get_current_frame ());
 	  ecs->step_after_step_resume_breakpoint = 1;
@@ -2536,8 +2553,7 @@ process_event_stop_test:
 	  && stop_signal != TARGET_SIGNAL_0
 	  && stop_pc >= step_range_start && stop_pc < step_range_end
 	  && frame_id_eq (get_frame_id (get_current_frame ()),
-			  step_frame_id)
-	  && step_resume_breakpoint == NULL)
+			  step_frame_id) && step_resume_breakpoint == NULL)
 	{
 	  /* The inferior is about to take a signal that will take it
 	     out of the single step range.  Set a breakpoint at the
@@ -2548,10 +2564,10 @@ process_event_stop_test:
 	     Note that this is only needed for a signal delivered
 	     while in the single-step range.  Nested signals aren't a
 	     problem as they eventually all return.  */
-          if (debug_infrun)
-            fprintf_unfiltered (gdb_stdlog,
-                                "infrun: signal may take us out of "
-                                "single-step range\n");
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: signal may take us out of "
+				"single-step range\n");
 
 	  insert_step_resume_breakpoint_at_frame (get_current_frame ());
 	  keep_going (ecs);
@@ -2559,11 +2575,11 @@ process_event_stop_test:
 	}
 
       /* Note: step_resume_breakpoint may be non-NULL.  This occures
-	 when either there's a nested signal, or when there's a
-	 pending signal enabled just as the signal handler returns
-	 (leaving the inferior at the step-resume-breakpoint without
-	 actually executing it).  Either way continue until the
-	 breakpoint is really hit.  */
+         when either there's a nested signal, or when there's a
+         pending signal enabled just as the signal handler returns
+         (leaving the inferior at the step-resume-breakpoint without
+         actually executing it).  Either way continue until the
+         breakpoint is really hit.  */
       keep_going (ecs);
       return;
     }
@@ -2595,7 +2611,8 @@ process_event_stop_test:
 
 	if (!gdbarch_get_longjmp_target_p (current_gdbarch)
 	    || !gdbarch_get_longjmp_target (current_gdbarch,
-					    get_current_frame (), &jmp_buf_pc))
+					    get_current_frame (),
+					    &jmp_buf_pc))
 	  {
 	    if (debug_infrun)
 	      fprintf_unfiltered (gdb_stdlog, "\
@@ -2616,7 +2633,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	return;
 
       case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME:
-        if (debug_infrun)
+	if (debug_infrun)
 	  fprintf_unfiltered (gdb_stdlog,
 			      "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n");
 
@@ -2629,7 +2646,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	return;
 
       case BPSTAT_WHAT_SINGLE:
-        if (debug_infrun)
+	if (debug_infrun)
 	  fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SINGLE\n");
 	ecs->stepping_over_breakpoint = 1;
 	/* Still need to check other stuff, at least the case
@@ -2637,7 +2654,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	break;
 
       case BPSTAT_WHAT_STOP_NOISY:
-        if (debug_infrun)
+	if (debug_infrun)
 	  fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_NOISY\n");
 	stop_print_frame = 1;
 
@@ -2648,8 +2665,9 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	return;
 
       case BPSTAT_WHAT_STOP_SILENT:
-        if (debug_infrun)
-	  fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STOP_SILENT\n");
+	if (debug_infrun)
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: BPSTAT_WHAT_STOP_SILENT\n");
 	stop_print_frame = 0;
 
 	/* We are about to nuke the step_resume_breakpoin via the
@@ -2676,8 +2694,9 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	   step-resume bp, but it makes no effort to ensure that
 	   the one deleted is the one currently stopped at.  MVS  */
 
-        if (debug_infrun)
-	  fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_STEP_RESUME\n");
+	if (debug_infrun)
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: BPSTAT_WHAT_STEP_RESUME\n");
 
 	if (step_resume_breakpoint == NULL)
 	  {
@@ -2711,8 +2730,9 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       case BPSTAT_WHAT_CHECK_SHLIBS:
       case BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK:
 	{
-          if (debug_infrun)
-	    fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CHECK_SHLIBS\n");
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: BPSTAT_WHAT_CHECK_SHLIBS\n");
 
 	  /* Check for any newly added shared libraries if we're
 	     supposed to be adding them automatically.  Switch
@@ -2818,15 +2838,16 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       /* Have we reached our destination?  If not, keep going. */
       if (SOLIB_IN_DYNAMIC_LINKER (PIDGET (ecs->ptid), stop_pc))
 	{
-          if (debug_infrun)
-	    fprintf_unfiltered (gdb_stdlog, "infrun: stepping in dynamic linker\n");
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: stepping in dynamic linker\n");
 	  ecs->stepping_over_breakpoint = 1;
 	  keep_going (ecs);
 	  return;
 	}
 #endif
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: step past dynamic linker\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: step past dynamic linker\n");
       /* Else, stop and report the catchpoint(s) whose triggering
          caused us to begin stepping. */
       ecs->stepping_through_solib_after_catch = 0;
@@ -2841,8 +2862,8 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
   if (step_resume_breakpoint)
     {
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog,
-			     "infrun: step-resume breakpoint is inserted\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: step-resume breakpoint is inserted\n");
 
       /* Having a step-resume breakpoint overrides anything
          else having to do with stepping commands until
@@ -2854,7 +2875,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
   if (step_range_end == 0)
     {
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: no stepping, continue\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: no stepping, continue\n");
       /* Likewise if we aren't even stepping.  */
       keep_going (ecs);
       return;
@@ -2868,13 +2889,14 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
   if (stop_pc >= step_range_start && stop_pc < step_range_end)
     {
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepping inside range [0x%s-0x%s]\n",
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: stepping inside range [0x%s-0x%s]\n",
 			    paddr_nz (step_range_start),
 			    paddr_nz (step_range_end));
 
       /* When stepping backward, stop at beginning of line range
-	 (unles it's the function entry point, in which case
-	 keep going back to the call point).  */
+         (unles it's the function entry point, in which case
+         keep going back to the call point).  */
       if (stop_pc == step_range_start &&
 	  stop_pc != ecs->stop_func_start &&
 	  target_get_execution_direction () == EXEC_REVERSE)
@@ -2902,13 +2924,14 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 #else
       && in_solib_dynsym_resolve_code (stop_pc)
 #endif
-      )
+    )
     {
       CORE_ADDR pc_after_resolver =
 	gdbarch_skip_solib_resolver (current_gdbarch, stop_pc);
 
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into dynsym resolve code\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: stepped into dynsym resolve code\n");
 
       if (pc_after_resolver)
 	{
@@ -2931,7 +2954,8 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       && get_frame_type (get_current_frame ()) == SIGTRAMP_FRAME)
     {
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into signal trampoline\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: stepped into signal trampoline\n");
       /* The inferior, while doing a "step" or "next", has ended up in
          a signal trampoline (either by a signal being delivered or by
          the signal handler returning).  Just single-step until the
@@ -2955,7 +2979,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       CORE_ADDR real_stop_pc;
 
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into subroutine\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: stepped into subroutine\n");
 
       if ((step_over_calls == STEP_OVER_NONE)
 	  || ((step_range_end == 1)
@@ -2987,15 +3011,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	     get there, we'll need to single-step back to the
 	     caller.  */
 
-	  if (target_get_execution_direction () == EXEC_REVERSE)
+	  if (target_get_execution_direction () == EXEC_REVERSE
+	      || RECORD_IS_USED)
 	    {
-	      /* FIXME: I'm not sure if we've handled the frame for
-		 recursion.  */
-
-	      struct symtab_and_line sr_sal;
-	      init_sal (&sr_sal);
-	      sr_sal.pc = ecs->stop_func_start;
-	      insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
+	      reverse_resume_need_step = 1;
 	    }
 	  else
 	    insert_step_resume_breakpoint_at_caller (get_current_frame ());
@@ -3012,17 +3031,17 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       real_stop_pc = skip_language_trampoline (get_current_frame (), stop_pc);
       if (real_stop_pc == 0)
 	real_stop_pc = gdbarch_skip_trampoline_code
-			 (current_gdbarch, get_current_frame (), stop_pc);
+	  (current_gdbarch, get_current_frame (), stop_pc);
       if (real_stop_pc != 0)
 	ecs->stop_func_start = real_stop_pc;
 
       if (
 #ifdef IN_SOLIB_DYNSYM_RESOLVE_CODE
-	  IN_SOLIB_DYNSYM_RESOLVE_CODE (ecs->stop_func_start)
+	   IN_SOLIB_DYNSYM_RESOLVE_CODE (ecs->stop_func_start)
 #else
-	  in_solib_dynsym_resolve_code (ecs->stop_func_start)
+	   in_solib_dynsym_resolve_code (ecs->stop_func_start)
 #endif
-)
+	)
 	{
 	  struct symtab_and_line sr_sal;
 	  init_sal (&sr_sal);
@@ -3071,6 +3090,10 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
 	  sr_sal.pc = ecs->stop_func_start;
 	  insert_step_resume_breakpoint_at_sal (sr_sal, null_frame_id);
 	}
+      else if (RECORD_IS_USED)
+	{
+	  reverse_resume_need_step = 1;
+	}
       else
 	{
 	  /* Set a breakpoint at callee's return address (the address
@@ -3089,10 +3112,11 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       /* Determine where this trampoline returns.  */
       CORE_ADDR real_stop_pc;
       real_stop_pc = gdbarch_skip_trampoline_code
-		       (current_gdbarch, get_current_frame (), stop_pc);
+	(current_gdbarch, get_current_frame (), stop_pc);
 
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into solib return tramp\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: stepped into solib return tramp\n");
 
       /* Only proceed through if we know where it's going.  */
       if (real_stop_pc)
@@ -3122,11 +3146,19 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
      the trampoline processing logic, however, there are some trampolines 
      that have no names, so we should do trampoline handling first.  */
   if (step_over_calls == STEP_OVER_UNDEBUGGABLE
-      && ecs->stop_func_name == NULL
-      && ecs->sal.line == 0)
+      && ecs->stop_func_name == NULL && ecs->sal.line == 0)
     {
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into undebuggable function\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: stepped into undebuggable function\n");
+
+      if (target_get_execution_direction () == EXEC_REVERSE || RECORD_IS_USED)
+	{
+	  reverse_resume_need_step = 1;
+	  keep_going (ecs);
+	  return;
+	}
+
 
       /* The inferior just stepped into, or returned to, an
          undebuggable function (where there is no debugging information
@@ -3162,7 +3194,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
       /* It is stepi or nexti.  We always want to stop stepping after
          one instruction.  */
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: stepi/nexti\n");
       stop_step = 1;
       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
@@ -3176,14 +3208,59 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
          when we do "s" in a function with no line numbers,
          or can this happen as a result of a return or longjmp?).  */
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n");
+	fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n");
+
+      if ((step_over_calls == STEP_OVER_ALL
+	   && target_get_execution_direction () == EXEC_REVERSE)
+	  || RECORD_IS_USED)
+	{
+	  reverse_resume_need_step = 1;
+	  keep_going (ecs);
+	  return;
+	}
+
       stop_step = 1;
       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
       return;
     }
 
-  if ((stop_pc == ecs->sal.pc)
+  if (target_get_execution_direction () == EXEC_REVERSE
+      && frame_id_eq (get_frame_id (get_current_frame ()),
+		      step_prev_frame_id))
+    {
+      if (debug_infrun)
+	{
+	  fprintf_unfiltered (gdb_stdlog,
+			      "infrun: return to the prev function\n");
+	}
+      stop_step = 1;
+      print_stop_reason (END_STEPPING_RANGE, 0);
+      stop_stepping (ecs);
+      return;
+    }
+
+  if (!frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id)
+      && (target_get_execution_direction () == EXEC_REVERSE
+	  || RECORD_IS_USED))
+    {
+      if ((stop_pc != ecs->sal.pc
+	   && target_get_execution_direction () == EXEC_REVERSE)
+	  || (step_over_calls == STEP_OVER_ALL && RECORD_IS_USED))
+	{
+	  if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog,
+				"infrun: maybe stepped into subroutine\n");
+	  reverse_resume_need_step = 1;
+	  keep_going (ecs);
+	  return;
+	}
+    }
+
+  if (((stop_pc == ecs->sal.pc
+	&& target_get_execution_direction () != EXEC_REVERSE)
+       || (stop_pc >= ecs->sal.pc && stop_pc < ecs->sal.end
+	   && target_get_execution_direction () == EXEC_REVERSE))
       && (ecs->current_line != ecs->sal.line
 	  || ecs->current_symtab != ecs->sal.symtab))
     {
@@ -3192,7 +3269,8 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
          That is said to make things like for (;;) statements work
          better.  */
       if (debug_infrun)
-	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n");
+	fprintf_unfiltered (gdb_stdlog,
+			    "infrun: stepped to a different line\n");
       stop_step = 1;
       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
@@ -3240,7 +3318,7 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
   }
 
   if (debug_infrun)
-     fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
+    fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
   keep_going (ecs);
 }
 
@@ -3252,7 +3330,7 @@ currently_stepping (struct execution_control_state *ecs)
   return (((step_range_end && step_resume_breakpoint == NULL)
 	   || stepping_over_breakpoint)
 	  || ecs->stepping_through_solib_after_catch
-	  || bpstat_should_step ());
+	  || bpstat_should_step () || reverse_resume_need_step);
 }
 
 /* Subroutine call with source code we should not step over.  Do step
@@ -3267,7 +3345,7 @@ step_into_function (struct execution_control_state *ecs)
   s = find_pc_symtab (stop_pc);
   if (s && s->language != language_asm)
     ecs->stop_func_start = gdbarch_skip_prologue
-			     (current_gdbarch, ecs->stop_func_start);
+      (current_gdbarch, ecs->stop_func_start);
 
   if (target_get_execution_direction () == EXEC_REVERSE)
     {
@@ -3283,10 +3361,10 @@ step_into_function (struct execution_control_state *ecs)
 	  return;
 	}
       /* Else just reset the step range and keep going.
-	 No step-resume breakpoint, they don't work for
-	 epilogues, which can have multiple entry paths.  */
+         No step-resume breakpoint, they don't work for
+         epilogues, which can have multiple entry paths.  */
       step_range_start = ecs->sal.pc;
-      step_range_end   = ecs->sal.end;
+      step_range_end = ecs->sal.end;
       keep_going (ecs);
       return;
     }
@@ -3389,7 +3467,7 @@ insert_step_resume_breakpoint_at_frame (struct frame_info *return_frame)
   init_sal (&sr_sal);		/* initialize to zeros */
 
   sr_sal.pc = gdbarch_addr_bits_remove
-		(current_gdbarch, get_frame_pc (return_frame));
+    (current_gdbarch, get_frame_pc (return_frame));
   sr_sal.section = find_pc_overlay (sr_sal.pc);
 
   insert_step_resume_breakpoint_at_sal (sr_sal, get_frame_id (return_frame));
@@ -3422,7 +3500,7 @@ insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame)
   init_sal (&sr_sal);		/* initialize to zeros */
 
   sr_sal.pc = gdbarch_addr_bits_remove
-		(current_gdbarch, frame_pc_unwind (next_frame));
+    (current_gdbarch, frame_pc_unwind (next_frame));
   sr_sal.section = find_pc_overlay (sr_sal.pc);
 
   insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id (next_frame));
@@ -3491,13 +3569,13 @@ keep_going (struct execution_control_state *ecs)
 
          We're going to run this baby now!  
 
-	 Note that insert_breakpoints won't try to re-insert
-	 already inserted breakpoints.  Therefore, we don't
-	 care if breakpoints were already inserted, or not.  */
-      
+         Note that insert_breakpoints won't try to re-insert
+         already inserted breakpoints.  Therefore, we don't
+         care if breakpoints were already inserted, or not.  */
+
       if (ecs->stepping_over_breakpoint)
 	{
-	  if (! use_displaced_stepping (current_gdbarch))
+	  if (!use_displaced_stepping (current_gdbarch))
 	    /* Since we can't do a displaced step, we have to remove
 	       the breakpoint while we step it.  To keep things
 	       simple, we remove them all.  */
@@ -3509,9 +3587,9 @@ keep_going (struct execution_control_state *ecs)
 	  /* Stop stepping when inserting breakpoints
 	     has failed.  */
 	  TRY_CATCH (e, RETURN_MASK_ERROR)
-	    {
-	      insert_breakpoints ();
-	    }
+	  {
+	    insert_breakpoints ();
+	  }
 	  if (e.reason < 0)
 	    {
 	      stop_stepping (ecs);
@@ -3619,7 +3697,7 @@ print_stop_reason (enum inferior_stop_reason stop_reason, int stop_info)
       if (stop_info)
 	{
 	  if (ui_out_is_mi_like_p (uiout))
-	    ui_out_field_string (uiout, "reason", 
+	    ui_out_field_string (uiout, "reason",
 				 async_reason_lookup (EXEC_ASYNC_EXITED));
 	  ui_out_text (uiout, "\nProgram exited with code ");
 	  ui_out_field_fmt (uiout, "exit-code", "0%o",
@@ -3773,8 +3851,8 @@ Further execution is probably impossible.\n"));
          what to print, based on the event(s) that just occurred. */
 
       /* If --batch-silent is enabled then there's no need to print the current
-	 source location, and to try risks causing an error message about
-	 missing source files.  */
+         source location, and to try risks causing an error message about
+         missing source files.  */
       if (stop_print_frame && !batch_silent)
 	{
 	  int bpstat_ret;
@@ -3786,12 +3864,13 @@ Further execution is probably impossible.\n"));
 	    {
 	    case PRINT_UNKNOWN:
 	      /* If we had hit a shared library event breakpoint,
-		 bpstat_print would print out this message.  If we hit
-		 an OS-level shared library event, do the same
-		 thing.  */
+	         bpstat_print would print out this message.  If we hit
+	         an OS-level shared library event, do the same
+	         thing.  */
 	      if (last.kind == TARGET_WAITKIND_LOADED)
 		{
-		  printf_filtered (_("Stopped due to shared library event\n"));
+		  printf_filtered (_
+				   ("Stopped due to shared library event\n"));
 		  source_flag = SRC_LINE;	/* something bogus */
 		  do_frame_printing = 0;
 		  break;
@@ -3847,7 +3926,7 @@ Further execution is probably impossible.\n"));
 	regcache_xfree (stop_registers);
 
       /* NB: The copy goes through to the target picking up the value of
-	 all the registers.  */
+         all the registers.  */
       stop_registers = regcache_dup (get_current_regcache ());
     }
 
@@ -4070,7 +4149,8 @@ handle_command (char *args, int from_tty)
 	  else
 	    {
 	      /* Not a number and not a recognized flag word => complain.  */
-	      error (_("Unrecognized or ambiguous flag word: \"%s\"."), *argv);
+	      error (_("Unrecognized or ambiguous flag word: \"%s\"."),
+		     *argv);
 	    }
 	}
 
@@ -4234,7 +4314,8 @@ signals_info (char *signum_exp, int from_tty)
 	sig_print_info (oursig);
     }
 
-  printf_filtered (_("\nUse the \"handle\" command to change these tables.\n"));
+  printf_filtered (_
+		   ("\nUse the \"handle\" command to change these tables.\n"));
 }
 
 struct inferior_status
@@ -4268,8 +4349,8 @@ struct inferior_status
 };
 
 void
-write_inferior_status_register (struct inferior_status *inf_status, int regno,
-				LONGEST val)
+write_inferior_status_register (struct inferior_status *inf_status,
+				int regno, LONGEST val)
 {
   int size = register_size (current_gdbarch, regno);
   void *buf = alloca (size);
@@ -4607,18 +4688,13 @@ of the program stops."), &cmdlist);
   add_setshow_zinteger_cmd ("infrun", class_maintenance, &debug_infrun, _("\
 Set inferior debugging."), _("\
 Show inferior debugging."), _("\
-When non-zero, inferior specific debugging is enabled."),
-			    NULL,
-			    show_debug_infrun,
-			    &setdebuglist, &showdebuglist);
+When non-zero, inferior specific debugging is enabled."), NULL, show_debug_infrun, &setdebuglist, &showdebuglist);
 
   add_setshow_boolean_cmd ("displaced", class_maintenance, &debug_displaced, _("\
 Set displaced stepping debugging."), _("\
 Show displaced stepping debugging."), _("\
 When non-zero, displaced stepping specific debugging is enabled."),
-			    NULL,
-			    show_debug_displaced,
-			    &setdebuglist, &showdebuglist);
+			   NULL, show_debug_displaced, &setdebuglist, &showdebuglist);
 
   numsigs = (int) TARGET_SIGNAL_LAST;
   signal_stop = (unsigned char *) xmalloc (sizeof (signal_stop[0]) * numsigs);
@@ -4673,10 +4749,7 @@ Set stopping for shared library events."), _("\
 Show stopping for shared library events."), _("\
 If nonzero, gdb will give control to the user when the dynamic linker\n\
 notifies gdb of shared library events.  The most common event of interest\n\
-to the user would be loading/unloading of a new library."),
-			    NULL,
-			    show_stop_on_solib_events,
-			    &setlist, &showlist);
+to the user would be loading/unloading of a new library."), NULL, show_stop_on_solib_events, &setlist, &showlist);
 
   add_setshow_enum_cmd ("follow-fork-mode", class_run,
 			follow_fork_mode_kind_names,
@@ -4687,23 +4760,17 @@ A fork or vfork creates a new process.  follow-fork-mode can be:\n\
   parent  - the original process is debugged after a fork\n\
   child   - the new process is debugged after a fork\n\
 The unfollowed process will continue to run.\n\
-By default, the debugger will follow the parent process."),
-			NULL,
-			show_follow_fork_mode_string,
-			&setlist, &showlist);
+By default, the debugger will follow the parent process."), NULL, show_follow_fork_mode_string, &setlist, &showlist);
 
-  add_setshow_enum_cmd ("scheduler-locking", class_run, 
-			scheduler_enums, &scheduler_mode, _("\
+  add_setshow_enum_cmd ("scheduler-locking", class_run, scheduler_enums, &scheduler_mode, _("\
 Set mode for locking scheduler during execution."), _("\
 Show mode for locking scheduler during execution."), _("\
 off  == no locking (threads may preempt at any time)\n\
 on   == full locking (no thread except the current thread may run)\n\
 step == scheduler locked during every single-step operation.\n\
 	In this mode, no other thread may run during a step command.\n\
-	Other threads may run while stepping over a function call ('next')."), 
-			set_schedlock_func,	/* traps on target vector */
-			show_scheduler_mode,
-			&setlist, &showlist);
+	Other threads may run while stepping over a function call ('next')."), set_schedlock_func,	/* traps on target vector */
+			show_scheduler_mode, &setlist, &showlist);
 
   add_setshow_boolean_cmd ("step-mode", class_run, &step_stop_if_no_debug, _("\
 Set mode of the step operation."), _("\
@@ -4711,20 +4778,14 @@ Show mode of the step operation."), _("\
 When set, doing a step over a function without debug line information\n\
 will stop at the first instruction of that function. Otherwise, the\n\
 function is skipped and the step command stops at a different source line."),
-			   NULL,
-			   show_step_stop_if_no_debug,
-			   &setlist, &showlist);
+			   NULL, show_step_stop_if_no_debug, &setlist, &showlist);
 
   add_setshow_boolean_cmd ("can-use-displaced-stepping", class_maintenance,
-			    &can_use_displaced_stepping, _("\
+			   &can_use_displaced_stepping, _("\
 Set debugger's willingness to use displaced stepping."), _("\
 Show debugger's willingness to use displaced stepping."), _("\
 If zero, gdb will not use to use displaced stepping to step over\n\
-breakpoints, even if such is supported by the target."),
-			    NULL,
-			    show_can_use_displaced_stepping,
-			    &maintenance_set_cmdlist,
-			   &maintenance_show_cmdlist);
+breakpoints, even if such is supported by the target."), NULL, show_can_use_displaced_stepping, &maintenance_set_cmdlist, &maintenance_show_cmdlist);
 
 
   /* ptid initializations */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 47dac59..6e26f15 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -50,6 +50,8 @@
 #include "event-loop.h"
 #include "event-top.h"
 
+#include "record.h"
+
 /* Note on this file's use of signals:
 
    We stop threads by sending a SIGSTOP.  The use of SIGSTOP instead
@@ -108,7 +110,7 @@
    with the ptrace event handlers also have __WALL, so it's safe to use
    here.  */
 #ifndef __WALL
-#define __WALL          0x40000000 /* Wait for any child.  */
+#define __WALL          0x40000000	/* Wait for any child.  */
 #endif
 
 #ifndef PTRACE_GETSIGINFO
@@ -125,11 +127,10 @@ static void (*linux_nat_new_thread) (ptid_t);
 
 /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
-static LONGEST (*super_xfer_partial) (struct target_ops *, 
+static LONGEST (*super_xfer_partial) (struct target_ops *,
 				      enum target_object,
-				      const char *, gdb_byte *, 
-				      const gdb_byte *,
-				      ULONGEST, LONGEST);
+				      const char *, gdb_byte *,
+				      const gdb_byte *, ULONGEST, LONGEST);
 
 static int debug_linux_nat;
 static void
@@ -145,7 +146,8 @@ static void
 show_debug_linux_nat_async (struct ui_file *file, int from_tty,
 			    struct cmd_list_element *c, const char *value)
 {
-  fprintf_filtered (file, _("Debugging of GNU/Linux async lwp module is %s.\n"),
+  fprintf_filtered (file,
+		    _("Debugging of GNU/Linux async lwp module is %s.\n"),
 		    value);
 }
 
@@ -204,11 +206,11 @@ static int linux_nat_async_events (int enable);
 static void pipe_to_local_event_queue (void);
 static void local_event_queue_to_pipe (void);
 static void linux_nat_event_pipe_push (int pid, int status, int options);
-static int linux_nat_event_pipe_pop (int* ptr_status, int* ptr_options);
+static int linux_nat_event_pipe_pop (int *ptr_status, int *ptr_options);
 static void linux_nat_set_async_mode (int on);
 static void linux_nat_async (void (*callback)
-			     (enum inferior_event_type event_type, void *context),
-			     void *context);
+			     (enum inferior_event_type event_type,
+			      void *context), void *context);
 static int linux_nat_async_mask (int mask);
 static int kill_lwp (int lwpid, int signo);
 
@@ -232,11 +234,8 @@ queued_waitpid (int pid, int *status, int flags)
   struct waitpid_result *msg = waitpid_queue, *prev = NULL;
 
   if (debug_linux_nat_async)
-    fprintf_unfiltered (gdb_stdlog,
-			"\
-QWPID: linux_nat_async_events_enabled(%d), linux_nat_num_queued_events(%d)\n",
-			linux_nat_async_events_enabled,
-			linux_nat_num_queued_events);
+    fprintf_unfiltered (gdb_stdlog, "\
+QWPID: linux_nat_async_events_enabled(%d), linux_nat_num_queued_events(%d)\n", linux_nat_async_events_enabled, linux_nat_num_queued_events);
 
   if (flags & __WALL)
     {
@@ -247,15 +246,13 @@ QWPID: linux_nat_async_events_enabled(%d), linux_nat_num_queued_events(%d)\n",
   else if (flags & __WCLONE)
     {
       for (; msg; prev = msg, msg = msg->next)
-	if (msg->options & __WCLONE
-	    && (pid == -1 || pid == msg->pid))
+	if (msg->options & __WCLONE && (pid == -1 || pid == msg->pid))
 	  break;
     }
   else
     {
       for (; msg; prev = msg, msg = msg->next)
-	if ((msg->options & __WCLONE) == 0
-	    && (pid == -1 || pid == msg->pid))
+	if ((msg->options & __WCLONE) == 0 && (pid == -1 || pid == msg->pid))
 	  break;
     }
 
@@ -302,9 +299,7 @@ push_waitpid (int pid, int status, int options)
 
   if (waitpid_queue)
     {
-      for (event = waitpid_queue;
-	   event && event->next;
-	   event = event->next)
+      for (event = waitpid_queue; event && event->next; event = event->next)
 	;
 
       event->next = new_event;
@@ -321,8 +316,8 @@ drain_queued_events (int pid)
   while (queued_waitpid (pid, NULL, __WALL) != -1)
     ;
 }
-
 
+
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
 static void
@@ -357,8 +352,8 @@ linux_record_stopped_pid (int pid, int status)
 {
   add_to_pid_list (&stopped_pids, pid, status);
 }
-
 
+
 /* A helper function for linux_test_for_tracefork, called after fork ().  */
 
 static void
@@ -396,6 +391,106 @@ my_waitpid (int pid, int *status, int flags)
   return ret;
 }
 
+extern struct bp_location *bp_location_chain;
+static int
+my_waitpid_record (int pid, int *status, int flags)
+{
+  int ret;
+  struct bp_location *bl;
+  struct breakpoint *b;
+  CORE_ADDR pc;
+
+wait_begin:
+  ret = waitpid (pid, status, flags);
+  if (ret == -1)
+    {
+      if (errno == EINTR)
+	{
+	  goto wait_begin;
+	}
+      return ret;
+    }
+
+  if (ret == 0)
+    {
+      goto wait_begin;
+    }
+
+  if (WIFSTOPPED (*status) && WSTOPSIG (*status) == SIGTRAP)
+    {
+      /* Check if there is a breakpoint */
+      pc = 0;
+      registers_changed ();
+      for (bl = bp_location_chain; bl; bl = bl->global_next)
+	{
+	  b = bl->owner;
+	  gdb_assert (b);
+	  if (b->enable_state != bp_enabled
+	      && b->enable_state != bp_permanent)
+	    continue;
+	  if (!pc)
+	    {
+	      pc = regcache_read_pc (get_thread_regcache (pid_to_ptid (ret)));
+	    }
+	  switch (b->type)
+	    {
+	    default:
+	      if (bl->address == pc)
+		{
+		  goto out;
+		}
+	      break;
+
+	    case bp_watchpoint:
+	      /*XXX teawater: I still not very clear how to deal with it. */
+	      goto out;
+	      break;
+
+	    case bp_catch_fork:
+	      if (inferior_has_forked (ret, &b->forked_inferior_pid))
+		{
+		  goto out;
+		}
+	      break;
+
+	    case bp_catch_vfork:
+	      if (inferior_has_vforked (ret, &b->forked_inferior_pid))
+		{
+		  goto out;
+		}
+	      break;
+
+	    case bp_catch_exec:
+	      if (inferior_has_execd (ret, &b->exec_pathname))
+		{
+		  goto out;
+		}
+	      break;
+
+	    case bp_hardware_watchpoint:
+	    case bp_read_watchpoint:
+	    case bp_access_watchpoint:
+	      if (STOPPED_BY_WATCHPOINT (0))
+		{
+		  goto out;
+		}
+	      break;
+
+	    }
+	}
+
+      /* record message */
+      record_message (current_gdbarch);
+
+      /* resume program */
+      linux_ops->to_resume (pid_to_ptid (ret), 1, TARGET_SIGNAL_0);
+      goto wait_begin;
+    }
+
+out:
+  return ret;
+}
+
 /* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.
 
    First, we try to enable fork tracing on ORIGINAL_PID.  If this fails,
@@ -433,9 +528,11 @@ linux_test_for_tracefork (int original_pid)
   if (ret == -1)
     perror_with_name (("waitpid"));
   else if (ret != child_pid)
-    error (_("linux_test_for_tracefork: waitpid: unexpected result %d."), ret);
-  if (! WIFSTOPPED (status))
-    error (_("linux_test_for_tracefork: waitpid: unexpected status %d."), status);
+    error (_("linux_test_for_tracefork: waitpid: unexpected result %d."),
+	   ret);
+  if (!WIFSTOPPED (status))
+    error (_("linux_test_for_tracefork: waitpid: unexpected status %d."),
+	   status);
 
   ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
   if (ret != 0)
@@ -449,10 +546,12 @@ linux_test_for_tracefork (int original_pid)
 
       ret = my_waitpid (child_pid, &status, 0);
       if (ret != child_pid)
-	warning (_("linux_test_for_tracefork: failed to wait for killed child"));
+	warning (_
+		 ("linux_test_for_tracefork: failed to wait for killed child"));
       else if (!WIFSIGNALED (status))
-	warning (_("linux_test_for_tracefork: unexpected wait status 0x%x from "
-		 "killed child"), status);
+	warning (_
+		 ("linux_test_for_tracefork: unexpected wait status 0x%x from "
+		  "killed child"), status);
 
       return;
     }
@@ -481,13 +580,14 @@ linux_test_for_tracefork (int original_pid)
 	  my_waitpid (second_pid, &second_status, 0);
 	  ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
 	  if (ret != 0)
-	    warning (_("linux_test_for_tracefork: failed to kill second child"));
+	    warning (_
+		     ("linux_test_for_tracefork: failed to kill second child"));
 	  my_waitpid (second_pid, &status, 0);
 	}
     }
   else
     warning (_("linux_test_for_tracefork: unexpected result from waitpid "
-	     "(%d, status 0x%x)"), ret, status);
+	       "(%d, status 0x%x)"), ret, status);
 
   ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
   if (ret != 0)
@@ -513,8 +613,8 @@ linux_supports_tracevforkdone (int pid)
     linux_test_for_tracefork (pid);
   return linux_supports_tracevforkdone_flag;
 }
-
 
+
 void
 linux_enable_event_reporting (ptid_t ptid)
 {
@@ -524,7 +624,7 @@ linux_enable_event_reporting (ptid_t ptid)
   if (pid == 0)
     pid = ptid_get_pid (ptid);
 
-  if (! linux_supports_tracefork (pid))
+  if (!linux_supports_tracefork (pid))
     return;
 
   options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
@@ -570,7 +670,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
     parent_pid = ptid_get_pid (last_ptid);
   child_pid = last_status.value.related_pid;
 
-  if (! follow_child)
+  if (!follow_child)
     {
       /* We're already attached to the parent, by default. */
 
@@ -578,7 +678,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
          it.  (This won't actually modify the breakpoint list, but will
          physically remove the breakpoints from the child.) */
       /* If we vforked this will remove the breakpoints from the parent
-	 also, but they'll be reinserted below.  */
+         also, but they'll be reinserted below.  */
       detach_breakpoints (child_pid);
 
       /* Detach new forked process?  */
@@ -615,40 +715,40 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
 	      my_waitpid (parent_pid, &status, __WALL);
 	      if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
 		warning (_("Unexpected waitpid result %06x when waiting for "
-			 "vfork-done"), status);
+			   "vfork-done"), status);
 	    }
 	  else
 	    {
 	      /* We can't insert breakpoints until the child has
-		 finished with the shared memory region.  We need to
-		 wait until that happens.  Ideal would be to just
-		 call:
-		 - ptrace (PTRACE_SYSCALL, parent_pid, 0, 0);
-		 - waitpid (parent_pid, &status, __WALL);
-		 However, most architectures can't handle a syscall
-		 being traced on the way out if it wasn't traced on
-		 the way in.
-
-		 We might also think to loop, continuing the child
-		 until it exits or gets a SIGTRAP.  One problem is
-		 that the child might call ptrace with PTRACE_TRACEME.
-
-		 There's no simple and reliable way to figure out when
-		 the vforked child will be done with its copy of the
-		 shared memory.  We could step it out of the syscall,
-		 two instructions, let it go, and then single-step the
-		 parent once.  When we have hardware single-step, this
-		 would work; with software single-step it could still
-		 be made to work but we'd have to be able to insert
-		 single-step breakpoints in the child, and we'd have
-		 to insert -just- the single-step breakpoint in the
-		 parent.  Very awkward.
-
-		 In the end, the best we can do is to make sure it
-		 runs for a little while.  Hopefully it will be out of
-		 range of any breakpoints we reinsert.  Usually this
-		 is only the single-step breakpoint at vfork's return
-		 point.  */
+	         finished with the shared memory region.  We need to
+	         wait until that happens.  Ideal would be to just
+	         call:
+	         - ptrace (PTRACE_SYSCALL, parent_pid, 0, 0);
+	         - waitpid (parent_pid, &status, __WALL);
+	         However, most architectures can't handle a syscall
+	         being traced on the way out if it wasn't traced on
+	         the way in.
+
+	         We might also think to loop, continuing the child
+	         until it exits or gets a SIGTRAP.  One problem is
+	         that the child might call ptrace with PTRACE_TRACEME.
+
+	         There's no simple and reliable way to figure out when
+	         the vforked child will be done with its copy of the
+	         shared memory.  We could step it out of the syscall,
+	         two instructions, let it go, and then single-step the
+	         parent once.  When we have hardware single-step, this
+	         would work; with software single-step it could still
+	         be made to work but we'd have to be able to insert
+	         single-step breakpoints in the child, and we'd have
+	         to insert -just- the single-step breakpoint in the
+	         parent.  Very awkward.
+
+	         In the end, the best we can do is to make sure it
+	         runs for a little while.  Hopefully it will be out of
+	         range of any breakpoints we reinsert.  Usually this
+	         is only the single-step breakpoint at vfork's return
+	         point.  */
 
 	      usleep (10000);
 	    }
@@ -663,7 +763,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       char child_pid_spelling[40];
 
       /* Needed to keep the breakpoint lists in sync.  */
-      if (! has_vforked)
+      if (!has_vforked)
 	detach_breakpoints (child_pid);
 
       /* Before detaching from the parent, remove all breakpoints from it. */
@@ -678,22 +778,22 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
 	}
 
       /* If we're vforking, we may want to hold on to the parent until
-	 the child exits or execs.  At exec time we can remove the old
-	 breakpoints from the parent and detach it; at exit time we
-	 could do the same (or even, sneakily, resume debugging it - the
-	 child's exec has failed, or something similar).
-
-	 This doesn't clean up "properly", because we can't call
-	 target_detach, but that's OK; if the current target is "child",
-	 then it doesn't need any further cleanups, and lin_lwp will
-	 generally not encounter vfork (vfork is defined to fork
-	 in libpthread.so).
-
-	 The holding part is very easy if we have VFORKDONE events;
-	 but keeping track of both processes is beyond GDB at the
-	 moment.  So we don't expose the parent to the rest of GDB.
-	 Instead we quietly hold onto it until such time as we can
-	 safely resume it.  */
+         the child exits or execs.  At exec time we can remove the old
+         breakpoints from the parent and detach it; at exit time we
+         could do the same (or even, sneakily, resume debugging it - the
+         child's exec has failed, or something similar).
+
+         This doesn't clean up "properly", because we can't call
+         target_detach, but that's OK; if the current target is "child",
+         then it doesn't need any further cleanups, and lin_lwp will
+         generally not encounter vfork (vfork is defined to fork
+         in libpthread.so).
+
+         The holding part is very easy if we have VFORKDONE events;
+         but keeping track of both processes is beyond GDB at the
+         moment.  So we don't expose the parent to the rest of GDB.
+         Instead we quietly hold onto it until such time as we can
+         safely resume it.  */
 
       if (has_vforked)
 	linux_parent_pid = parent_pid;
@@ -712,7 +812,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       inferior_ptid = ptid_build (child_pid, child_pid, 0);
 
       /* Reinstall ourselves, since we might have been removed in
-	 target_detach (which does other necessary cleanup).  */
+         target_detach (which does other necessary cleanup).  */
 
       push_target (ops);
       linux_nat_switch_fork (inferior_ptid);
@@ -727,12 +827,12 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
 
   return 0;
 }
-
 
+
 static void
 linux_child_insert_fork_catchpoint (int pid)
 {
-  if (! linux_supports_tracefork (pid))
+  if (!linux_supports_tracefork (pid))
     error (_("Your system does not support fork catchpoints."));
 }
 
@@ -820,8 +920,8 @@ static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_nat_thread_alive (ptid_t ptid);
 static char *linux_child_pid_to_exec_file (int pid);
 static int cancel_breakpoint (struct lwp_info *lp);
-
 
+
 /* Convert wait status STATUS to a string.  Used for printing debug
    messages only.  */
 
@@ -1001,7 +1101,7 @@ prune_lwps (void)
   struct saved_ptids **p = &threads_to_delete;
 
   while (*p)
-    if (! ptid_equal ((*p)->ptid, inferior_ptid))
+    if (!ptid_equal ((*p)->ptid, inferior_ptid))
       {
 	struct saved_ptids *tmp = *p;
 	delete_thread (tmp->ptid);
@@ -1082,22 +1182,22 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned,
 			    "LNPAW: Attaching to a stopped process\n");
 
       /* The process is definitely stopped.  It is in a job control
-	 stop, unless the kernel predates the TASK_STOPPED /
-	 TASK_TRACED distinction, in which case it might be in a
-	 ptrace stop.  Make sure it is in a ptrace stop; from there we
-	 can kill it, signal it, et cetera.
+         stop, unless the kernel predates the TASK_STOPPED /
+         TASK_TRACED distinction, in which case it might be in a
+         ptrace stop.  Make sure it is in a ptrace stop; from there we
+         can kill it, signal it, et cetera.
 
          First make sure there is a pending SIGSTOP.  Since we are
-	 already attached, the process can not transition from stopped
-	 to running without a PTRACE_CONT; so we know this signal will
-	 go into the queue.  The SIGSTOP generated by PTRACE_ATTACH is
-	 probably already in the queue (unless this kernel is old
-	 enough to use TASK_STOPPED for ptrace stops); but since SIGSTOP
-	 is not an RT signal, it can only be queued once.  */
+         already attached, the process can not transition from stopped
+         to running without a PTRACE_CONT; so we know this signal will
+         go into the queue.  The SIGSTOP generated by PTRACE_ATTACH is
+         probably already in the queue (unless this kernel is old
+         enough to use TASK_STOPPED for ptrace stops); but since SIGSTOP
+         is not an RT signal, it can only be queued once.  */
       kill_lwp (pid, SIGSTOP);
 
       /* Finally, resume the stopped process.  This will deliver the SIGSTOP
-	 (or a higher priority signal, just like normal PTRACE_ATTACH).  */
+         (or a higher priority signal, just like normal PTRACE_ATTACH).  */
       ptrace (PTRACE_CONT, pid, 0, 0);
     }
 
@@ -1258,7 +1358,8 @@ linux_nat_attach (char *args, int from_tty)
     }
 
   /* Add the initial process as the first LWP to the list.  */
-  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+  inferior_ptid =
+    BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
   lp = add_lwp (inferior_ptid);
 
   status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned,
@@ -1281,8 +1382,8 @@ linux_nat_attach (char *args, int from_tty)
   else
     {
       /* We already waited for this LWP, so put the wait result on the
-	 pipe.  The event loop will wake up and gets us to handling
-	 this event.  */
+         pipe.  The event loop will wake up and gets us to handling
+         this event.  */
       linux_nat_event_pipe_push (GET_PID (lp->ptid), status,
 				 lp->cloned ? __WCLONE : 0);
       /* Register in the event loop.  */
@@ -1308,8 +1409,7 @@ get_pending_status (struct lwp_info *lp, int *status)
   *status = 0;
   if (GET_LWP (lp->ptid) == GET_LWP (last_ptid))
     {
-      if (stop_signal != TARGET_SIGNAL_0
-	  && signal_pass_state (stop_signal))
+      if (stop_signal != TARGET_SIGNAL_0 && signal_pass_state (stop_signal))
 	*status = W_STOPCODE (target_signal_to_host (stop_signal));
     }
   else if (target_can_async_p ())
@@ -1386,17 +1486,15 @@ linux_nat_detach (char *args, int from_tty)
 
   /* Pass on any pending signal for the last LWP.  */
   if ((args == NULL || *args == '\0')
-      && get_pending_status (lwp_list, &status) != -1
-      && WIFSTOPPED (status))
+      && get_pending_status (lwp_list, &status) != -1 && WIFSTOPPED (status))
     {
       /* Put the signal number in ARGS so that inf_ptrace_detach will
-	 pass it along with PTRACE_DETACH.  */
+         pass it along with PTRACE_DETACH.  */
       args = alloca (8);
       sprintf (args, "%d", (int) WSTOPSIG (status));
       fprintf_unfiltered (gdb_stdlog,
 			  "LND: Sending signal %s to %s\n",
-			  args,
-			  target_pid_to_str (lwp_list->ptid));
+			  args, target_pid_to_str (lwp_list->ptid));
     }
 
   /* Destroy LWP info; it's no longer valid.  */
@@ -1525,7 +1623,7 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
   if (lp->status)
     {
       /* FIXME: What should we do if we are supposed to continue
-	 this thread with a signal?  */
+         this thread with a signal?  */
       gdb_assert (signo == TARGET_SIGNAL_0);
 
       if (debug_linux_nat)
@@ -1593,8 +1691,7 @@ kill_lwp (int lwpid, int signo)
    true, the new LWP remains stopped, otherwise it is continued.  */
 
 static int
-linux_handle_extended_wait (struct lwp_info *lp, int status,
-			    int stopping)
+linux_handle_extended_wait (struct lwp_info *lp, int status, int stopping)
 {
   int pid = GET_LWP (lp->ptid);
   struct target_waitstatus *ourstatus = &lp->waitstatus;
@@ -1610,7 +1707,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
       ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid);
 
       /* If we haven't already seen the new PID stop, wait for it now.  */
-      if (! pull_pid_from_list (&stopped_pids, new_pid, &status))
+      if (!pull_pid_from_list (&stopped_pids, new_pid, &status))
 	{
 	  /* The new child has a pending SIGSTOP.  We can't affect it until it
 	     hits the SIGSTOP, but we're already attached.  */
@@ -1623,7 +1720,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 			    _("wait returned unexpected PID %d"), ret);
 	  else if (!WIFSTOPPED (status))
 	    internal_error (__FILE__, __LINE__,
-			    _("wait returned unexpected status 0x%x"), status);
+			    _("wait returned unexpected status 0x%x"),
+			    status);
 	}
 
       ourstatus->value.related_pid = new_pid;
@@ -1641,12 +1739,12 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 	  if (WSTOPSIG (status) != SIGSTOP)
 	    {
 	      /* This can happen if someone starts sending signals to
-		 the new thread before it gets a chance to run, which
-		 have a lower number than SIGSTOP (e.g. SIGUSR1).
-		 This is an unlikely case, and harder to handle for
-		 fork / vfork than for clone, so we do not try - but
-		 we handle it for clone events here.  We'll send
-		 the other signal on to the thread below.  */
+	         the new thread before it gets a chance to run, which
+	         have a lower number than SIGSTOP (e.g. SIGUSR1).
+	         This is an unlikely case, and harder to handle for
+	         fork / vfork than for clone, so we do not try - but
+	         we handle it for clone events here.  We'll send
+	         the other signal on to the thread below.  */
 
 	      new_lp->signalled = 1;
 	    }
@@ -1691,8 +1789,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
       return 0;
     }
 
-  internal_error (__FILE__, __LINE__,
-		  _("unknown ptrace event %d"), event);
+  internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event);
 }
 
 /* Wait for LP to stop.  Returns the wait status, or 0 if the LWP has
@@ -1757,12 +1854,12 @@ wait_lwp (struct lwp_info *lp)
   gdb_assert (WIFSTOPPED (status));
 
   /* Handle GNU/Linux's extended waitstatus for trace events.  */
-  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
+      && status >> 16 != 0)
     {
       if (debug_linux_nat)
 	fprintf_unfiltered (gdb_stdlog,
-			    "WL: Handling extended status 0x%06x\n",
-			    status);
+			    "WL: Handling extended status 0x%06x\n", status);
       if (linux_handle_extended_wait (lp, status, 1))
 	return wait_lwp (lp);
     }
@@ -1889,7 +1986,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 				      target_pid_to_str (lp->ptid));
 		}
 	      /* Hold this event/waitstatus while we check to see if
-		 there are any more (we still want to get that SIGSTOP). */
+	         there are any more (we still want to get that SIGSTOP). */
 	      stop_wait_callback (lp, data);
 
 	      if (target_can_async_p ())
@@ -1899,7 +1996,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 		  if (!cancel_breakpoint (lp))
 		    {
 		      /* There was no gdb breakpoint set at pc.  Put
-			 the event back in the queue.  */
+		         the event back in the queue.  */
 		      if (debug_linux_nat)
 			fprintf_unfiltered (gdb_stdlog,
 					    "SWC: kill %s, %s\n",
@@ -1954,8 +2051,8 @@ stop_wait_callback (struct lwp_info *lp, void *data)
 	      stop_wait_callback (lp, data);
 
 	      /* If the lp->status field is still empty, use it to
-		 hold this event.  If not, then this event must be
-		 returned to the event queue of the LWP.  */
+	         hold this event.  If not, then this event must be
+	         returned to the event queue of the LWP.  */
 	      if (lp->status || target_can_async_p ())
 		{
 		  if (debug_linux_nat)
@@ -1988,7 +2085,7 @@ stop_wait_callback (struct lwp_info *lp, void *data)
    the appropriate bits in PENDING, and return 1 - otherwise return 0.  */
 
 static int
-linux_nat_has_pending (int pid, sigset_t *pending, sigset_t *flush_mask)
+linux_nat_has_pending (int pid, sigset_t * pending, sigset_t * flush_mask)
 {
   sigset_t blocked, ignored;
   int i;
@@ -2001,8 +2098,7 @@ linux_nat_has_pending (int pid, sigset_t *pending, sigset_t *flush_mask)
   for (i = 1; i < NSIG; i++)
     if (sigismember (pending, i))
       if (!sigismember (flush_mask, i)
-	  || sigismember (&blocked, i)
-	  || sigismember (&ignored, i))
+	  || sigismember (&blocked, i) || sigismember (&ignored, i))
 	sigdelset (pending, i);
 
   if (sigisemptyset (pending))
@@ -2041,7 +2137,8 @@ flush_callback (struct lwp_info *lp, void *data)
     {
       if (debug_linux_nat)
 	printf_unfiltered (_("FC: LP has pending status %06x\n"), lp->status);
-      if (WIFSTOPPED (lp->status) && sigismember (flush_mask, WSTOPSIG (lp->status)))
+      if (WIFSTOPPED (lp->status)
+	  && sigismember (flush_mask, WSTOPSIG (lp->status)))
 	lp->status = 0;
     }
 
@@ -2056,7 +2153,7 @@ flush_callback (struct lwp_info *lp, void *data)
 	 && linux_nat_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
     {
       int ret;
-      
+
       errno = 0;
       ret = ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
       if (debug_linux_nat)
@@ -2326,8 +2423,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
       if (options & __WCLONE)
 	lp->cloned = 1;
 
-      gdb_assert (WIFSTOPPED (status)
-		  && WSTOPSIG (status) == SIGSTOP);
+      gdb_assert (WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
       lp->signalled = 1;
 
       if (!in_thread_list (inferior_ptid))
@@ -2345,12 +2441,12 @@ linux_nat_filter_event (int lwpid, int status, int options)
     save_siginfo (lp);
 
   /* Handle GNU/Linux's extended waitstatus for trace events.  */
-  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
+      && status >> 16 != 0)
     {
       if (debug_linux_nat)
 	fprintf_unfiltered (gdb_stdlog,
-			    "LLW: Handling extended status 0x%06x\n",
-			    status);
+			    "LLW: Handling extended status 0x%06x\n", status);
       if (linux_handle_extended_wait (lp, status, 0))
 	return NULL;
     }
@@ -2359,15 +2455,15 @@ linux_nat_filter_event (int lwpid, int status, int options)
   if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
     {
       /* If this is the main thread, we must stop all threads and
-	 verify if they are still alive.  This is because in the nptl
-	 thread model, there is no signal issued for exiting LWPs
-	 other than the main thread.  We only get the main thread exit
-	 signal once all child threads have already exited.  If we
-	 stop all the threads and use the stop_wait_callback to check
-	 if they have exited we can determine whether this signal
-	 should be ignored or whether it means the end of the debugged
-	 application, regardless of which threading model is being
-	 used.  */
+         verify if they are still alive.  This is because in the nptl
+         thread model, there is no signal issued for exiting LWPs
+         other than the main thread.  We only get the main thread exit
+         signal once all child threads have already exited.  If we
+         stop all the threads and use the stop_wait_callback to check
+         if they have exited we can determine whether this signal
+         should be ignored or whether it means the end of the debugged
+         application, regardless of which threading model is being
+         used.  */
       if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
 	{
 	  lp->stopped = 1;
@@ -2382,8 +2478,8 @@ linux_nat_filter_event (int lwpid, int status, int options)
       exit_lwp (lp);
 
       /* If there is at least one more LWP, then the exit signal was
-	 not the end of the debugged application and should be
-	 ignored.  */
+         not the end of the debugged application and should be
+         ignored.  */
       if (num_lwps > 0)
 	{
 	  /* Make sure there is at least one thread running.  */
@@ -2416,8 +2512,7 @@ linux_nat_filter_event (int lwpid, int status, int options)
 
   /* Make sure we don't report a SIGSTOP that we sent ourselves in
      an attempt to stop an LWP.  */
-  if (lp->signalled
-      && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
+  if (lp->signalled && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
     {
       if (debug_linux_nat)
 	fprintf_unfiltered (gdb_stdlog,
@@ -2482,9 +2577,7 @@ local_event_queue_to_pipe (void)
   while (w)
     {
       struct waitpid_result *next = w->next;
-      linux_nat_event_pipe_push (w->pid,
-				 w->status,
-				 w->options);
+      linux_nat_event_pipe_push (w->pid, w->status, w->options);
       xfree (w);
       w = next;
     }
@@ -2630,7 +2723,16 @@ retry:
 	   queued events.  */
 	lwpid = queued_waitpid (pid, &status, options);
       else
-	lwpid = my_waitpid (pid, &status, options);
+	{
+	  if (RECORD_IS_USED && !record_resume_step)
+	    {
+	      lwpid = my_waitpid_record (pid, &status, options);
+	    }
+	  else
+	    {
+	      lwpid = my_waitpid (pid, &status, options);
+	    }
+	}
 
       if (lwpid > 0)
 	{
@@ -2706,7 +2808,7 @@ retry:
       int signo = target_signal_from_host (WSTOPSIG (status));
 
       /* If we get a signal while single-stepping, we may need special
-	 care, e.g. to skip the signal handler.  Defer to common code.  */
+         care, e.g. to skip the signal handler.  Defer to common code.  */
       if (!lp->step
 	  && signal_stop_state (signo) == 0
 	  && signal_print_state (signo) == 0
@@ -2825,17 +2927,17 @@ kill_wait_callback (struct lwp_info *lp, void *data)
       do
 	{
 	  pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
-	  if (pid != (pid_t) -1)
+	  if (pid != (pid_t) - 1)
 	    {
 	      if (debug_linux_nat)
 		fprintf_unfiltered (gdb_stdlog,
 				    "KWC: wait %s received unknown.\n",
 				    target_pid_to_str (lp->ptid));
 	      /* The Linux kernel sometimes fails to kill a thread
-		 completely after PTRACE_KILL; that goes from the stop
-		 point in do_fork out to the one in
-		 get_signal_to_deliever and waits again.  So kill it
-		 again.  */
+	         completely after PTRACE_KILL; that goes from the stop
+	         point in do_fork out to the one in
+	         get_signal_to_deliever and waits again.  So kill it
+	         again.  */
 	      kill_callback (lp, NULL);
 	    }
 	}
@@ -2847,7 +2949,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
   do
     {
       pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
-      if (pid != (pid_t) -1)
+      if (pid != (pid_t) - 1)
 	{
 	  if (debug_linux_nat)
 	    fprintf_unfiltered (gdb_stdlog,
@@ -2909,7 +3011,7 @@ linux_nat_mourn_inferior (void)
   /* Destroy LWP info; it's no longer valid.  */
   init_lwp_list ();
 
-  if (! forks_exist_p ())
+  if (!forks_exist_p ())
     {
       /* Normal case, no other forks available.  */
       if (target_can_async_p ())
@@ -2925,8 +3027,8 @@ linux_nat_mourn_inferior (void)
 
 static LONGEST
 linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
-			const char *annex, gdb_byte *readbuf,
-			const gdb_byte *writebuf,
+			const char *annex, gdb_byte * readbuf,
+			const gdb_byte * writebuf,
 			ULONGEST offset, LONGEST len)
 {
   struct cleanup *old_chain = save_inferior_ptid ();
@@ -2972,8 +3074,7 @@ linux_nat_pid_to_str (ptid_t ptid)
   static char buf[64];
 
   if (is_lwp (ptid)
-      && ((lwp_list && lwp_list->next)
-	  || GET_PID (ptid) != GET_LWP (ptid)))
+      && ((lwp_list && lwp_list->next) || GET_PID (ptid) != GET_LWP (ptid)))
     {
       snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
       return buf;
@@ -2986,8 +3087,7 @@ static void
 sigchld_handler (int signo)
 {
   if (linux_nat_async_enabled
-      && linux_nat_async_events_enabled
-      && signo == SIGCHLD)
+      && linux_nat_async_events_enabled && signo == SIGCHLD)
     /* It is *always* a bug to hit this.  */
     internal_error (__FILE__, __LINE__,
 		    "sigchld_handler called when async events are enabled");
@@ -3021,7 +3121,7 @@ linux_child_pid_to_exec_file (int pid)
 /* Service function for corefiles and info proc.  */
 
 static int
-read_mapping (FILE *mapfile,
+read_mapping (FILE * mapfile,
 	      long long *addr,
 	      long long *endaddr,
 	      char *permissions,
@@ -3053,7 +3153,8 @@ read_mapping (FILE *mapfile,
 static int
 linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
 					    unsigned long,
-					    int, int, int, void *), void *obfd)
+					    int, int, int, void *),
+			       void *obfd)
 {
   long long pid = PIDGET (inferior_ptid);
   char mapsfilename[MAXPATHLEN];
@@ -3096,7 +3197,7 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
 	}
 
       /* Invoke the callback function to create the corefile
-	 segment.  */
+         segment.  */
       func (addr, size, read, write, exec, obfd);
     }
   fclose (mapsfile);
@@ -3107,7 +3208,7 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
    section.  */
 
 static char *
-linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
+linux_nat_do_thread_registers (bfd * obfd, ptid_t ptid,
 			       char *note_data, int *note_size)
 {
   gdb_gregset_t gregs;
@@ -3133,16 +3234,14 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
 						     sizeof (gregs))) != NULL
       && regset->collect_regset != NULL)
-    regset->collect_regset (regset, regcache, -1,
-			    &gregs, sizeof (gregs));
+    regset->collect_regset (regset, regcache, -1, &gregs, sizeof (gregs));
   else
     fill_gregset (regcache, &gregs, -1);
 
   note_data = (char *) elfcore_write_prstatus (obfd,
 					       note_data,
 					       note_size,
-					       lwp,
-					       stop_signal, &gregs);
+					       lwp, stop_signal, &gregs);
 
   /* The loop below uses the new struct core_regset_section, which stores
      the supported section names and sizes for the core file.  Note that
@@ -3167,7 +3266,8 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
 	note_data = (char *) elfcore_write_register_note (obfd,
 							  note_data,
 							  note_size,
-							  sect_list->sect_name,
+							  sect_list->
+							  sect_name,
 							  gdb_regset,
 							  sect_list->size);
 	xfree (gdb_regset);
@@ -3180,11 +3280,11 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
   else
     {
       if (core_regset_p
-          && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
-							 sizeof (fpregs))) != NULL
-	  && regset->collect_regset != NULL)
-	regset->collect_regset (regset, regcache, -1,
-				&fpregs, sizeof (fpregs));
+	  && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
+							 sizeof (fpregs))) !=
+	  NULL && regset->collect_regset != NULL)
+	regset->collect_regset (regset, regcache, -1, &fpregs,
+				sizeof (fpregs));
       else
 	fill_fpregset (regcache, &fpregs, -1);
 
@@ -3225,13 +3325,14 @@ linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
 /* Records the register state for the corefile note section.  */
 
 static char *
-linux_nat_do_registers (bfd *obfd, ptid_t ptid,
+linux_nat_do_registers (bfd * obfd, ptid_t ptid,
 			char *note_data, int *note_size)
 {
   return linux_nat_do_thread_registers (obfd,
-					ptid_build (ptid_get_pid (inferior_ptid),
-						    ptid_get_pid (inferior_ptid),
-						    0),
+					ptid_build (ptid_get_pid
+						    (inferior_ptid),
+						    ptid_get_pid
+						    (inferior_ptid), 0),
 					note_data, note_size);
 }
 
@@ -3239,7 +3340,7 @@ linux_nat_do_registers (bfd *obfd, ptid_t ptid,
    section for a corefile, and returns it in a malloc buffer.  */
 
 static char *
-linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
+linux_nat_make_corefile_notes (bfd * obfd, int *note_size)
 {
   struct linux_nat_corefile_thread_data thread_args;
   struct cleanup *old_chain;
@@ -3425,16 +3526,16 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
 	  if (gdbarch_addr_bit (current_gdbarch) == 32)
 	    {
 	      printf_filtered ("\t%10s %10s %10s %10s %7s\n",
-			   "Start Addr",
-			   "  End Addr",
-			   "      Size", "    Offset", "objfile");
-            }
+			       "Start Addr",
+			       "  End Addr",
+			       "      Size", "    Offset", "objfile");
+	    }
 	  else
-            {
+	    {
 	      printf_filtered ("  %18s %18s %10s %10s %7s\n",
-			   "Start Addr",
-			   "  End Addr",
-			   "      Size", "    Offset", "objfile");
+			       "Start Addr",
+			       "  End Addr",
+			       "      Size", "    Offset", "objfile");
 	    }
 
 	  while (read_mapping (procfile, &addr, &endaddr, &permissions[0],
@@ -3443,29 +3544,27 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
 	      size = endaddr - addr;
 
 	      /* FIXME: carlton/2003-08-27: Maybe the printf_filtered
-		 calls here (and possibly above) should be abstracted
-		 out into their own functions?  Andrew suggests using
-		 a generic local_address_string instead to print out
-		 the addresses; that makes sense to me, too.  */
+	         calls here (and possibly above) should be abstracted
+	         out into their own functions?  Andrew suggests using
+	         a generic local_address_string instead to print out
+	         the addresses; that makes sense to me, too.  */
 
 	      if (gdbarch_addr_bit (current_gdbarch) == 32)
-	        {
-	          printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
-			       (unsigned long) addr,	/* FIXME: pr_addr */
-			       (unsigned long) endaddr,
-			       (int) size,
-			       (unsigned int) offset,
-			       filename[0] ? filename : "");
+		{
+		  printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n", (unsigned long) addr,	/* FIXME: pr_addr */
+				   (unsigned long) endaddr,
+				   (int) size,
+				   (unsigned int) offset,
+				   filename[0] ? filename : "");
 		}
 	      else
-	        {
-	          printf_filtered ("  %#18lx %#18lx %#10x %#10x %7s\n",
-			       (unsigned long) addr,	/* FIXME: pr_addr */
-			       (unsigned long) endaddr,
-			       (int) size,
-			       (unsigned int) offset,
-			       filename[0] ? filename : "");
-	        }
+		{
+		  printf_filtered ("  %#18lx %#18lx %#10x %#10x %7s\n", (unsigned long) addr,	/* FIXME: pr_addr */
+				   (unsigned long) endaddr,
+				   (int) size,
+				   (unsigned int) offset,
+				   filename[0] ? filename : "");
+		}
 	    }
 
 	  fclose (procfile);
@@ -3533,7 +3632,8 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
 	  if (fscanf (procfile, "%ld ", &ltmp) > 0)
 	    printf_filtered (_("stime, children: %ld\n"), ltmp);
 	  if (fscanf (procfile, "%ld ", &ltmp) > 0)
-	    printf_filtered (_("jiffies remaining in current time slice: %ld\n"),
+	    printf_filtered (_
+			     ("jiffies remaining in current time slice: %ld\n"),
 			     ltmp);
 	  if (fscanf (procfile, "%ld ", &ltmp) > 0)
 	    printf_filtered (_("'nice' value: %ld\n"), ltmp);
@@ -3544,13 +3644,15 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
 	    printf_filtered (_("jiffies until next SIGALRM: %lu\n"),
 			     (unsigned long) ltmp);
 	  if (fscanf (procfile, "%ld ", &ltmp) > 0)
-	    printf_filtered (_("start time (jiffies since system boot): %ld\n"),
+	    printf_filtered (_
+			     ("start time (jiffies since system boot): %ld\n"),
 			     ltmp);
 	  if (fscanf (procfile, "%lu ", &ltmp) > 0)
 	    printf_filtered (_("Virtual memory size: %lu\n"),
 			     (unsigned long) ltmp);
 	  if (fscanf (procfile, "%lu ", &ltmp) > 0)
-	    printf_filtered (_("Resident set size: %lu\n"), (unsigned long) ltmp);
+	    printf_filtered (_("Resident set size: %lu\n"),
+			     (unsigned long) ltmp);
 	  if (fscanf (procfile, "%lu ", &ltmp) > 0)
 	    printf_filtered (_("rlim: %lu\n"), (unsigned long) ltmp);
 	  if (fscanf (procfile, "%lu ", &ltmp) > 0)
@@ -3590,8 +3692,8 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
 
 static LONGEST
 linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
-			 const char *annex, gdb_byte *readbuf,
-			 const gdb_byte *writebuf,
+			 const char *annex, gdb_byte * readbuf,
+			 const gdb_byte * writebuf,
 			 ULONGEST offset, LONGEST len)
 {
   LONGEST ret;
@@ -3632,7 +3734,7 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object,
 /* Parse LINE as a signal set and add its set bits to SIGS.  */
 
 static void
-add_line_to_sigset (const char *line, sigset_t *sigs)
+add_line_to_sigset (const char *line, sigset_t * sigs)
 {
   int len = strlen (line) - 1;
   const char *p;
@@ -3673,7 +3775,8 @@ add_line_to_sigset (const char *line, sigset_t *sigs)
    SIGS to match.  */
 
 void
-linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored)
+linux_proc_pending_signals (int pid, sigset_t * pending, sigset_t * blocked,
+			    sigset_t * ignored)
 {
   FILE *procfile;
   char buffer[MAXPATHLEN], fname[MAXPATHLEN];
@@ -3690,12 +3793,12 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
   while (fgets (buffer, MAXPATHLEN, procfile) != NULL)
     {
       /* Normal queued signals are on the SigPnd line in the status
-	 file.  However, 2.6 kernels also have a "shared" pending
-	 queue for delivering signals to a thread group, so check for
-	 a ShdPnd line also.
+         file.  However, 2.6 kernels also have a "shared" pending
+         queue for delivering signals to a thread group, so check for
+         a ShdPnd line also.
 
-	 Unfortunately some Red Hat kernels include the shared pending
-	 queue but not the ShdPnd status field.  */
+         Unfortunately some Red Hat kernels include the shared pending
+         queue but not the ShdPnd status field.  */
 
       if (strncmp (buffer, "SigPnd:\t", 8) == 0)
 	add_line_to_sigset (buffer + 8, pending);
@@ -3712,8 +3815,8 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
 
 static LONGEST
 linux_xfer_partial (struct target_ops *ops, enum target_object object,
-                    const char *annex, gdb_byte *readbuf,
-		    const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+		    const char *annex, gdb_byte * readbuf,
+		    const gdb_byte * writebuf, ULONGEST offset, LONGEST len)
 {
   LONGEST xfer;
 
@@ -3762,7 +3865,8 @@ linux_target (void)
 }
 
 struct target_ops *
-linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int))
+linux_trad_target (CORE_ADDR (*register_u_offset)
+		   (struct gdbarch *, int, int))
 {
   struct target_ops *t;
 
@@ -3781,7 +3885,7 @@ static int linux_async_permitted_1 = 0;
 
 static void
 set_maintenance_linux_async_permitted (char *args, int from_tty,
-			       struct cmd_list_element *c)
+				       struct cmd_list_element *c)
 {
   if (target_has_execution)
     {
@@ -3795,11 +3899,11 @@ set_maintenance_linux_async_permitted (char *args, int from_tty,
 
 static void
 show_maintenance_linux_async_permitted (struct ui_file *file, int from_tty,
-			    struct cmd_list_element *c, const char *value)
+					struct cmd_list_element *c,
+					const char *value)
 {
   fprintf_filtered (file, _("\
-Controlling the GNU/Linux inferior in asynchronous mode is %s.\n"),
-		    value);
+Controlling the GNU/Linux inferior in asynchronous mode is %s.\n"), value);
 }
 
 /* target_is_async_p implementation.  */
@@ -3865,9 +3969,9 @@ linux_nat_async_mask (int mask)
 /* Pop an event from the event pipe.  */
 
 static int
-linux_nat_event_pipe_pop (int* ptr_status, int* ptr_options)
+linux_nat_event_pipe_pop (int *ptr_status, int *ptr_options)
 {
-  struct waitpid_result event = {0};
+  struct waitpid_result event = { 0 };
   int ret;
 
   do
@@ -3892,7 +3996,7 @@ static void
 linux_nat_event_pipe_push (int pid, int status, int options)
 {
   int ret;
-  struct waitpid_result event = {0};
+  struct waitpid_result event = { 0 };
   event.pid = pid;
   event.status = status;
   event.options = options;
@@ -3901,7 +4005,8 @@ linux_nat_event_pipe_push (int pid, int status, int options)
     {
       ret = write (linux_nat_event_pipe[1], &event, sizeof (event));
       gdb_assert ((ret == -1 && errno == EINTR) || ret == sizeof (event));
-    } while (ret == -1 && errno == EINTR);
+    }
+  while (ret == -1 && errno == EINTR);
 
   linux_nat_num_queued_events++;
 }
@@ -3942,16 +4047,14 @@ get_pending_events (void)
 
       if (debug_linux_nat_async)
 	fprintf_unfiltered (gdb_stdlog, "\
-get_pending_events: pid(%d), status(%x), options (%x)\n",
-			    pid, status, options);
+get_pending_events: pid(%d), status(%x), options (%x)\n", pid, status, options);
 
       linux_nat_event_pipe_push (pid, status, options);
     }
 
   if (debug_linux_nat_async)
     fprintf_unfiltered (gdb_stdlog, "\
-get_pending_events: linux_nat_num_queued_events(%d)\n",
-			linux_nat_num_queued_events);
+get_pending_events: linux_nat_num_queued_events(%d)\n", linux_nat_num_queued_events);
 }
 
 /* SIGCHLD handler for async mode.  */
@@ -4224,29 +4327,19 @@ Specify any of the following keywords for detailed info:\n\
 			    &debug_linux_nat, _("\
 Set debugging of GNU/Linux lwp module."), _("\
 Show debugging of GNU/Linux lwp module."), _("\
-Enables printf debugging output."),
-			    NULL,
-			    show_debug_linux_nat,
-			    &setdebuglist, &showdebuglist);
+Enables printf debugging output."), NULL, show_debug_linux_nat, &setdebuglist, &showdebuglist);
 
   add_setshow_zinteger_cmd ("lin-lwp-async", class_maintenance,
 			    &debug_linux_nat_async, _("\
 Set debugging of GNU/Linux async lwp module."), _("\
 Show debugging of GNU/Linux async lwp module."), _("\
-Enables printf debugging output."),
-			    NULL,
-			    show_debug_linux_nat_async,
-			    &setdebuglist, &showdebuglist);
+Enables printf debugging output."), NULL, show_debug_linux_nat_async, &setdebuglist, &showdebuglist);
 
   add_setshow_boolean_cmd ("linux-async", class_maintenance,
 			   &linux_async_permitted_1, _("\
 Set whether gdb controls the GNU/Linux inferior in asynchronous mode."), _("\
 Show whether gdb controls the GNU/Linux inferior in asynchronous mode."), _("\
-Tells gdb whether to control the GNU/Linux inferior in asynchronous mode."),
-			   set_maintenance_linux_async_permitted,
-			   show_maintenance_linux_async_permitted,
-			   &maintenance_set_cmdlist,
-			   &maintenance_show_cmdlist);
+Tells gdb whether to control the GNU/Linux inferior in asynchronous mode."), set_maintenance_linux_async_permitted, show_maintenance_linux_async_permitted, &maintenance_set_cmdlist, &maintenance_show_cmdlist);
 
   /* Block SIGCHLD by default.  Doing this early prevents it getting
      unblocked if an exception is thrown due to an error while the
@@ -4298,7 +4391,7 @@ get_signo (const char *name)
   if (ms == NULL)
     return 0;
 
-  if (target_read_memory (SYMBOL_VALUE_ADDRESS (ms), (gdb_byte *) &signo,
+  if (target_read_memory (SYMBOL_VALUE_ADDRESS (ms), (gdb_byte *) & signo,
 			  sizeof (signo)) != 0)
     return 0;
 
@@ -4308,7 +4401,7 @@ get_signo (const char *name)
 /* Return the set of signals used by the threads library in *SET.  */
 
 void
-lin_thread_get_thread_signals (sigset_t *set)
+lin_thread_get_thread_signals (sigset_t * set)
 {
   struct sigaction action;
   int restart, cancel;
diff --git a/gdb/record.c b/gdb/record.c
new file mode 100644
index 0000000..4cab7a0
--- /dev/null
+++ b/gdb/record.c
@@ -0,0 +1,867 @@
+/* Record v0.1.6 for GDB, the GNU debugger.
+   Written by Hui Zhu <teawater@gmail.com>
+
+   Copyright (C) 2008 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "inferior.h"
+#include "record.h"
+
+#include <signal.h>
+
+int record_debug = 0;
+record_t record_first;
+record_t *record_list = &record_first;
+int record_list_status = 1;	/* 0 normal 1 to the begin 2 to the end */
+record_t *record_arch_list_head = NULL;
+record_t *record_arch_list_tail = NULL;
+struct regcache *record_regcache = NULL;
+
+struct target_ops record_ops;
+int record_resume_step = 0;
+enum exec_direction_kind record_execdir = EXEC_FORWARD;
+static int record_get_sig = 0;
+static sigset_t record_maskall;
+static int record_not_record = 0;
+int record_regcache_raw_write_regnum = 0;
+int record_will_store_registers = 0;
+
+extern struct breakpoint *breakpoint_chain;
+extern ptid_t displaced_step_ptid;
+extern CORE_ADDR displaced_step_original, displaced_step_copy;
+
+static void
+record_list_release (record_t * rec)
+{
+  record_t *tmp;
+
+  if (!rec)
+    return;
+
+  while (rec->next)
+    {
+      rec = rec->next;
+    }
+
+  while (rec->prev)
+    {
+      tmp = rec;
+      rec = rec->prev;
+      if (tmp->type == record_reg)
+	{
+	  xfree (tmp->u.reg.val);
+	}
+      else if (tmp->type == record_mem)
+	{
+	  xfree (tmp->u.mem.val);
+	}
+      xfree (tmp);
+    }
+
+  if (rec != &record_first)
+    {
+      xfree (rec);
+    }
+}
+
+static void
+record_list_release_next (record_t * rec)
+{
+  record_t *tmp = rec->next;
+  rec->next = NULL;
+  while (tmp)
+    {
+      rec = tmp->next;
+      if (tmp->type == record_reg)
+	{
+	  xfree (tmp->u.reg.val);
+	}
+      else if (tmp->type == record_mem)
+	{
+	  xfree (tmp->u.mem.val);
+	}
+      xfree (tmp);
+      tmp = rec;
+    }
+}
+
+/* Add a record_t to "record_arch_list". */
+static void
+record_arch_list_add (record_t * rec)
+{
+  if (record_arch_list_tail)
+    {
+      record_arch_list_tail->next = rec;
+      rec->prev = record_arch_list_tail;
+      record_arch_list_tail = rec;
+    }
+  else
+    {
+      record_arch_list_head = rec;
+      record_arch_list_tail = rec;
+    }
+}
+
+/* Record the value of a register("num") to "record_arch_list". */
+int
+record_arch_list_add_reg (int num)
+{
+  record_t *rec;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+			  "Record: add reg num = %d to record list.\n", num);
+    }
+
+  rec = (record_t *) xmalloc (sizeof (record_t));
+  rec->u.reg.val = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE);
+  rec->prev = NULL;
+  rec->next = NULL;
+  rec->type = record_reg;
+  rec->u.reg.num = num;
+
+  regcache_raw_read (record_regcache, num, rec->u.reg.val);
+
+  record_arch_list_add (rec);
+
+  return (0);
+}
+
+/* Record the value of a part of memroy that address is "addr" and length is
+   "len" to "record_arch_list". */
+int
+record_arch_list_add_mem (CORE_ADDR addr, int len)
+{
+  record_t *rec;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+			  "Record: add mem addr = 0x%s len = %d to record list.\n",
+			  paddr_nz (addr), len);
+    }
+
+  if (!addr)
+    {
+      return (0);
+    }
+
+  rec = (record_t *) xmalloc (sizeof (record_t));
+  rec->u.mem.val = (gdb_byte *) xmalloc (len);
+  rec->prev = NULL;
+  rec->next = NULL;
+  rec->type = record_mem;
+  rec->u.mem.addr = addr;
+  rec->u.mem.len = len;
+
+  if (target_read_memory (addr, rec->u.mem.val, len))
+    {
+      fprintf_unfiltered (gdb_stdlog,
+			  "Record: read memory addr = 0x%s len = %d error.\n",
+			  paddr_nz (addr), len);
+      xfree (rec->u.mem.val);
+      xfree (rec);
+      return (-1);
+    }
+
+  record_arch_list_add (rec);
+
+  return (0);
+}
+
+/* Add a "record_end" type record_t to "record_arch_list". */
+int
+record_arch_list_add_end (int need_dasm)
+{
+  record_t *rec;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+			  "Record: add end need_dasm = %d to arch list.\n",
+			  need_dasm);
+    }
+
+  rec = (record_t *) xmalloc (sizeof (record_t));
+  rec->prev = NULL;
+  rec->next = NULL;
+  rec->type = record_end;
+
+  rec->u.need_dasm = need_dasm;
+
+  record_arch_list_add (rec);
+
+  return (0);
+}
+
+/* Before inferior step (When GDB record the running message, inferior only can
+   step.), GDB will call this function to record the values to "record_list".
+   This function will call "gdbarch_record" to record the running message of
+   inferior and set them to "record_arch_list". And add it to "record_list". */
+void
+record_message (struct gdbarch *gdbarch)
+{
+  int ret;
+
+  record_arch_list_head = NULL;
+  record_arch_list_tail = NULL;
+  record_regcache = get_current_regcache ();
+
+  /* Deal with displaced stepping */
+  if (!ptid_equal (displaced_step_ptid, null_ptid))
+    {
+      if (record_debug)
+	{
+	  fprintf_unfiltered (gdb_stdlog,
+			      "Record: this stepping is displaced stepping. Change PC register to original address 0x%s before call gdbarch_record. After that, change it back to 0x%s.\n",
+			      paddr_nz (displaced_step_original),
+			      paddr_nz (displaced_step_copy));
+	}
+      regcache_write_pc (record_regcache, displaced_step_original);
+      ret = gdbarch_record (gdbarch, displaced_step_copy);
+      regcache_write_pc (record_regcache, displaced_step_copy);
+    }
+  else
+    {
+      ret = gdbarch_record (gdbarch, regcache_read_pc (record_regcache));
+    }
+
+  if (ret > 0)
+    {
+      record_list_release (record_arch_list_tail);
+      error (_("Record: record pause the program."));
+    }
+  if (ret < 0)
+    {
+      record_list_release (record_arch_list_tail);
+      error (_("Record: record message error."));
+    }
+
+  record_list->next = record_arch_list_head;
+  record_arch_list_head->prev = record_list;
+  record_list = record_arch_list_tail;
+}
+
+/* Things to clean up if we QUIT out of function that set record_not_record.  */
+static void
+record_not_record_cleanups (void *ignore)
+{
+  record_not_record = 0;
+}
+
+void
+record_not_record_set (void)
+{
+  struct cleanup *old_cleanups = make_cleanup (record_not_record_cleanups, 0);
+  record_not_record = 1;
+}
+
+static void
+record_open (char *name, int from_tty)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: record_open\n");
+    }
+
+  /* check exec */
+  if (!target_has_execution)
+    {
+      error (_("Record: the program is not being run."));
+    }
+
+  if (!gdbarch_record_p (current_gdbarch))
+    {
+      error (_
+	     ("Record: the current architecture don't support record function."));
+    }
+
+  /* Check if record target is already running */
+  if (RECORD_IS_USED)
+    {
+      if (!nquery
+	  (_
+	   ("Record target already running, do you want delete the old running message?")))
+	{
+	  return;
+	}
+    }
+
+  push_target (&record_ops);
+}
+
+static void
+record_close (int quitting)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: record_close\n");
+    }
+  record_list_release (record_list);
+  record_list_status = 1;
+  record_execdir = EXEC_FORWARD;
+}
+
+static void
+record_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+  record_resume_step = step;
+
+  if (!RECORD_IS_REPLAY)
+    {
+      record_message (current_gdbarch);
+      return record_ops.beneath->to_resume (ptid, 1, siggnal);
+    }
+}
+
+static void
+record_sig_handler (int signo)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: get a signal\n");
+    }
+  record_resume_step = 1;
+  record_get_sig = 1;
+}
+
+static ptid_t
+record_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: record_resume_step = %d\n",
+			  record_resume_step);
+    }
+
+  if (!RECORD_IS_REPLAY)
+    {
+      return record_ops.beneath->to_wait (ptid, status);
+    }
+  else
+    {
+      struct sigaction act, old_act;
+      int need_dasm = 0;
+      struct regcache *regcache = get_current_regcache ();
+      int con = 1;
+      int first_record_end = 1;
+
+      record_get_sig = 0;
+      act.sa_handler = record_sig_handler;
+      act.sa_mask = record_maskall;
+      act.sa_flags = SA_RESTART;
+      if (sigaction (SIGINT, &act, &old_act))
+	{
+	  perror_with_name (_("Record: sigaction"));
+	}
+
+      do
+	{
+
+	  /* check state */
+	  if ((record_execdir == EXEC_REVERSE && !record_list->prev
+	       && record_list_status == 1) || (record_execdir != EXEC_REVERSE
+					       && !record_list->next
+					       && record_list_status == 2))
+	    {
+	      if (record_list_status == 2)
+		{
+		  fprintf_unfiltered (gdb_stdlog,
+				      "Record: running to the end of record list.\n");
+		}
+	      else if (record_list_status == 1)
+		{
+		  fprintf_unfiltered (gdb_stdlog,
+				      "Record: running to the begin of record list.\n");
+		}
+	      stop_soon = STOP_QUIETLY;
+	      break;
+	    }
+	  record_list_status = 0;
+
+	  /* set register and memory according to record_list */
+	  if (record_list->type == record_reg)
+	    {
+	      /* reg */
+	      gdb_byte reg[MAX_REGISTER_SIZE];
+	      if (record_debug > 1)
+		{
+		  fprintf_unfiltered (gdb_stdlog,
+				      "Record: record_reg to inferior num = %d.\n",
+				      record_list->u.reg.num);
+		}
+	      regcache_cooked_read (regcache, record_list->u.reg.num, reg);
+	      regcache_cooked_write (regcache, record_list->u.reg.num,
+				     record_list->u.reg.val);
+	      memcpy (record_list->u.reg.val, reg, MAX_REGISTER_SIZE);
+	    }
+	  else if (record_list->type == record_mem)
+	    {
+	      /* mem */
+	      gdb_byte *mem = alloca (record_list->u.mem.len);
+	      if (record_debug > 1)
+		{
+		  fprintf_unfiltered (gdb_stdlog,
+				      "Record: record_mem to inferior addr = 0x%s len = %d.\n",
+				      paddr_nz (record_list->u.mem.addr),
+				      record_list->u.mem.len);
+		}
+	      if (target_read_memory
+		  (record_list->u.mem.addr, mem, record_list->u.mem.len))
+		{
+		  error (_("Record: read memory addr = 0x%s len = %d error."),
+			 paddr_nz (record_list->u.mem.addr),
+			 record_list->u.mem.len);
+		}
+	      if (target_write_memory
+		  (record_list->u.mem.addr, record_list->u.mem.val,
+		   record_list->u.mem.len))
+		{
+		  error (_
+			 ("Record: write memory addr = 0x%s len = %d error."),
+			 paddr_nz (record_list->u.mem.addr),
+			 record_list->u.mem.len);
+		}
+	      memcpy (record_list->u.mem.val, mem, record_list->u.mem.len);
+	    }
+	  else
+	    {
+	      CORE_ADDR tmp_pc;
+	      struct breakpoint *b;
+
+	      if (record_debug > 1)
+		{
+		  fprintf_unfiltered (gdb_stdlog,
+				      "Record: record_end to inferior need_dasm = %d.\n",
+				      record_list->u.need_dasm);
+		}
+
+	      if (record_execdir == EXEC_FORWARD)
+		{
+		  need_dasm = record_list->u.need_dasm;
+		}
+	      if (need_dasm)
+		{
+		  gdbarch_record_dasm (current_gdbarch);
+		}
+
+	      if (first_record_end && record_execdir == EXEC_REVERSE)
+		{
+		  /* When reverse excute, the first record_end is the part of current instruction */
+		  first_record_end = 0;
+		}
+	      else
+		{
+		  /* In EXEC_REVERSE mode, this is the record_end of prev
+		     instruction.
+		     In EXEC_FORWARD mode, this is the record_end of current
+		     instruction. */
+		  /* step */
+		  if (record_resume_step)
+		    {
+		      if (record_debug > 1)
+			{
+			  fprintf_unfiltered (gdb_stdlog, "Record: step.\n");
+			}
+		      con = 0;
+		    }
+
+		  /* check breakpoint */
+		  tmp_pc = read_pc ();
+		  for (b = breakpoint_chain; b; b = b->next)
+		    {
+		      if (b->loc->inserted)
+			{
+			  if (b->loc->target_info.placed_address == tmp_pc)
+			    {
+			      if (record_debug > 1)
+				{
+				  fprintf_unfiltered (gdb_stdlog,
+						      "Record: break at 0x%s.\n",
+						      paddr_nz (tmp_pc));
+				}
+			      con = 0;
+			    }
+			}
+		    }
+		}
+	      if (record_execdir == EXEC_REVERSE)
+		{
+		  need_dasm = record_list->u.need_dasm;
+		}
+	    }
+
+	  if (record_execdir == EXEC_REVERSE)
+	    {
+	      if (record_list->prev && con)
+		record_list = record_list->prev;
+	      else
+		record_list_status = 1;
+	    }
+	  else
+	    {
+	      if (record_list->next)
+		record_list = record_list->next;
+	      else
+		record_list_status = 2;
+	    }
+
+	}
+      while (con);
+
+      if (sigaction (SIGALRM, &old_act, NULL))
+	{
+	  perror_with_name (_("Record: sigaction"));
+	}
+
+      status->kind = TARGET_WAITKIND_STOPPED;
+      if (record_get_sig)
+	{
+	  status->value.sig = TARGET_SIGNAL_INT;
+	}
+      else
+	{
+	  status->value.sig = TARGET_SIGNAL_TRAP;
+	}
+    }
+
+  return inferior_ptid;
+}
+
+static void
+record_disconnect (struct target_ops *target, char *args, int from_tty)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: record_disconnect\n");
+    }
+  unpush_target (&record_ops);
+  target_disconnect (args, from_tty);
+}
+
+static void
+record_detach (char *args, int from_tty)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: record_detach\n");
+    }
+  unpush_target (&record_ops);
+  target_detach (args, from_tty);
+}
+
+/* Close record target before kill the inferior process. */
+static void
+record_kill (void)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Record: record_kill\n");
+    }
+  unpush_target (&record_ops);
+  target_kill ();
+}
+
+/* Record registers change to list as an instruction */
+static void
+record_registers_change (struct regcache *regcache, int regnum)
+{
+  record_arch_list_head = NULL;
+  record_arch_list_tail = NULL;
+  record_regcache = get_current_regcache ();
+  if (regnum < 0)
+    {
+      int i;
+      for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
+	{
+	  if (record_arch_list_add_reg (i))
+	    {
+	      record_list_release (record_arch_list_tail);
+	      error (_("Record: record message error."));
+	    }
+	}
+    }
+  else
+    {
+      if (record_arch_list_add_reg (regnum))
+	{
+	  record_list_release (record_arch_list_tail);
+	  error (_("Record: record message error."));
+	}
+    }
+  if (record_arch_list_add_end (0))
+    {
+      record_list_release (record_arch_list_tail);
+      error (_("Record: record message error."));
+    }
+  record_list->next = record_arch_list_head;
+  record_arch_list_head->prev = record_list;
+  record_list = record_arch_list_tail;
+}
+
+/* XXX: I don't know how to do if GDB call function target_store_registers
+   without call function target_prepare_to_store. */
+static void
+record_prepare_to_store (struct regcache *regcache)
+{
+  if (!record_not_record)
+    {
+      if (RECORD_IS_REPLAY)
+	{
+	  struct cleanup *old_cleanups;
+	  /* Let user choice if he want to write register or not. */
+	  if (!nquery (_
+		       ("Becuse GDB is in replay mode, this operation will destory the record in the next if set the value of register %s. Do you want GDB do it?"),
+		       gdbarch_register_name (get_regcache_arch
+					      (regcache),
+					      record_regcache_raw_write_regnum)))
+	    {
+	      error (_("Record: record cancel the operation."));
+	    }
+
+	  /* Destory the record in the next */
+	  record_list_release_next (record_list);
+	}
+
+      record_registers_change (regcache, record_regcache_raw_write_regnum);
+    }
+  record_ops.beneath->to_prepare_to_store (regcache);
+}
+
+static LONGEST
+record_xfer_partial (struct target_ops *ops, enum target_object object,
+		     const char *annex, gdb_byte * readbuf,
+		     const gdb_byte * writebuf, ULONGEST offset, LONGEST len)
+{
+  if (!record_not_record
+      && (object == TARGET_OBJECT_MEMORY
+	  || object == TARGET_OBJECT_RAW_MEMORY) && writebuf)
+    {
+      if (RECORD_IS_REPLAY)
+	{
+	  /* Let user choice if he want to write memory or not. */
+	  if (!nquery (_
+		       ("Becuse GDB is in replay mode, this operation will destory the record in the next if write memory that addr is 0x%s and size is %lld. Do you want GDB do it?"),
+		       paddr_nz (offset), len))
+	    {
+	      return -1;
+	    }
+
+	  /* Destory the record in the next */
+	  record_list_release_next (record_list);
+	}
+
+      /* Record registers change to list as an instruction */
+      record_arch_list_head = NULL;
+      record_arch_list_tail = NULL;
+      record_regcache = get_current_regcache ();
+      if (record_arch_list_add_mem (offset, len))
+	{
+	  record_list_release (record_arch_list_tail);
+	  fprintf_unfiltered (gdb_stdlog, _("Record: record message error."));
+	  return -1;
+	}
+      if (record_arch_list_add_end (0))
+	{
+	  record_list_release (record_arch_list_tail);
+	  fprintf_unfiltered (gdb_stdlog, _("Record: record message error."));
+	  return -1;
+	}
+      record_list->next = record_arch_list_head;
+      record_arch_list_head->prev = record_list;
+      record_list = record_arch_list_tail;
+    }
+
+  return record_ops.beneath->to_xfer_partial (ops, object, annex, readbuf,
+					      writebuf, offset, len);
+}
+
+static int
+record_insert_breakpoint (struct bp_target_info *bp_tgt)
+{
+  if (!RECORD_IS_REPLAY)
+    {
+      return record_ops.beneath->to_insert_breakpoint (bp_tgt);
+    }
+
+  return 0;
+}
+
+static int
+record_remove_breakpoint (struct bp_target_info *bp_tgt)
+{
+  if (!RECORD_IS_REPLAY)
+    {
+      return record_ops.beneath->to_remove_breakpoint (bp_tgt);
+    }
+
+  return 0;
+}
+
+static enum exec_direction_kind
+record_get_execdir (void)
+{
+  if (record_debug > 1)
+    printf_filtered ("Record: execdir is %s\n",
+		     record_execdir == EXEC_FORWARD ? "forward" :
+		     record_execdir == EXEC_REVERSE ? "reverse" : "unknown");
+  return record_execdir;
+}
+
+static int
+record_set_execdir (enum exec_direction_kind dir)
+{
+  if (record_debug)
+    printf_filtered ("Record: set execdir: %s\n",
+		     dir == EXEC_FORWARD ? "forward" :
+		     dir == EXEC_REVERSE ? "reverse" : "bad direction");
+
+  /* FIXME: check target for capability.  */
+  if (dir == EXEC_FORWARD || dir == EXEC_REVERSE)
+    return (record_execdir = dir);
+  else
+    return EXEC_ERROR;
+}
+
+static void
+init_record_ops (void)
+{
+  record_ops.to_shortname = "record";
+  record_ops.to_longname = "Record and reverse target";
+  record_ops.to_doc =
+    "Record the program running message and replay this message.";
+  record_ops.to_open = record_open;
+  record_ops.to_close = record_close;
+  record_ops.to_resume = record_resume;
+  record_ops.to_wait = record_wait;
+  record_ops.to_disconnect = record_disconnect;
+  record_ops.to_detach = record_detach;
+  record_ops.to_kill = record_kill;
+  record_ops.to_create_inferior = find_default_create_inferior;	/* Make record suppport command "run". */
+  record_ops.to_prepare_to_store = record_prepare_to_store;
+  record_ops.to_xfer_partial = record_xfer_partial;
+  record_ops.to_insert_breakpoint = record_insert_breakpoint;
+  record_ops.to_remove_breakpoint = record_remove_breakpoint;
+  record_ops.to_get_execdir = record_get_execdir;
+  record_ops.to_set_execdir = record_set_execdir;
+  record_ops.to_stratum = record_stratum;
+  record_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+show_record_debug (struct ui_file *file, int from_tty,
+		   struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Debugging of record target is %s.\n"), value);
+}
+
+static void
+cmd_record_start (char *args, int from_tty)
+{
+  execute_command ("target record", from_tty);
+}
+
+static void
+cmd_record_delete (char *args, int from_tty)
+{
+  if (RECORD_IS_USED)
+    {
+      if (RECORD_IS_REPLAY)
+	{
+	  if (!from_tty || query (_
+				  ("Record: delete the next running messages and begin to record the running message at current address?")))
+	    {
+	      record_list_release_next (record_list);
+	    }
+	}
+      else
+	{
+	  printf_unfiltered (_
+			     ("Record: GDB already at the end of record list.\n"));
+	}
+
+    }
+  else
+    {
+      printf_unfiltered (_("Record: record target is not started.\n"));
+    }
+}
+
+static void
+cmd_record_stop (char *args, int from_tty)
+{
+  if (RECORD_IS_USED)
+    {
+      if (!record_list || !from_tty || query (_
+					      ("Record: delete all the record messages and stop record target?")))
+	{
+	  unpush_target (&record_ops);
+	}
+    }
+  else
+    {
+      printf_unfiltered (_("Record: record target is not started.\n"));
+    }
+}
+
+void
+_initialize_record (void)
+{
+  /* init record_maskall */
+  if (sigfillset (&record_maskall) == -1)
+    {
+      perror_with_name (_("Record: sigfillset"));
+    }
+
+  /* init record_first */
+  record_first.prev = NULL;
+  record_first.next = NULL;
+  record_first.type = record_end;
+  record_first.u.need_dasm = 0;
+
+  init_record_ops ();
+  add_target (&record_ops);
+
+  add_setshow_zinteger_cmd ("record", no_class, &record_debug,
+			    _("Set record debugging."),
+			    _("Show record debugging."),
+			    _
+			    ("When non-zero, record specific debugging is enabled."),
+			    NULL, show_record_debug, &setdebuglist,
+			    &showdebuglist);
+
+  add_com ("record", class_obscure, cmd_record_start,
+	   _("Same with command \"target record\"."));
+  add_com_alias ("rec", "record", class_obscure, 1);
+
+  /* XXX: I try to use some simple commands such as "disconnect" and "detach"
+     to support this functions. But these commands all have other affect to
+     GDB such as call function "no_shared_libraries". So I add special commands
+     to GDB. */
+  add_com ("delrecord", class_obscure, cmd_record_delete,
+	   _
+	   ("When record target running in replay mode, delete the next running messages and begin to record the running message at current address."));
+  add_com_alias ("dr", "delrecord", class_obscure, 1);
+  add_com ("stoprecord", class_obscure, cmd_record_stop,
+	   _("Stop the record target."));
+  add_com_alias ("sr", "stoprecord", class_obscure, 1);
+}
diff --git a/gdb/record.h b/gdb/record.h
new file mode 100644
index 0000000..2547dab
--- /dev/null
+++ b/gdb/record.h
@@ -0,0 +1,86 @@
+/* Record v0.1.5 for GDB, the GNU debugger.
+   Written by Hui Zhu <teawater@gmail.com>
+
+   Copyright (C) 2008 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _RECORD_H_
+#define _RECORD_H_
+
+#define RECORD_IS_USED		(current_target.beneath == &record_ops)
+#define RECORD_IS_REPLAY	(record_list->next || record_execdir == EXEC_REVERSE)
+
+typedef struct record_reg_s
+{
+  int num;
+  gdb_byte *val;
+} record_reg_t;
+
+typedef struct record_mem_s
+{
+  CORE_ADDR addr;
+  int len;
+  gdb_byte *val;
+} record_mem_t;
+
+enum record_type
+{
+  record_end = 0,
+  record_reg,
+  record_mem
+};
+
+/* This is the core struct of record function.
+   An entity of record_t is a record of the value change of a register
+   ("record_reg") or a part of memory ("record_mem"). And Each instruction must
+   has a record_t ("record_end") that point out this is the last record_t of
+   this instruction.
+   Each record_t is linked to "record_list" by "prev" and "next". 
+ */
+typedef struct record_s
+{
+  struct record_s *prev;
+  struct record_s *next;
+  enum record_type type;
+  union
+  {
+    /* reg */
+    record_reg_t reg;
+    /* mem */
+    record_mem_t mem;
+    /* end */
+    int need_dasm;
+  } u;
+} record_t;
+
+extern int record_debug;
+extern record_t *record_list;
+extern record_t *record_arch_list_head;
+extern record_t *record_arch_list_tail;
+extern struct regcache *record_regcache;
+
+extern struct target_ops record_ops;
+extern int record_resume_step;
+extern int record_regcache_raw_write_regnum;
+extern enum exec_direction_kind record_execdir;
+
+extern int record_arch_list_add_reg (int num);
+extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
+extern int record_arch_list_add_end (int need_dasm);
+extern void record_message (struct gdbarch *gdbarch);
+extern void record_not_record_set (void);
+#endif /* _RECORD_H_ */
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 199b626..bf54bb7 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -29,6 +29,7 @@
 #include "gdb_string.h"
 #include "gdbcmd.h"		/* For maintenanceprintlist.  */
 #include "observer.h"
+#include "record.h"
 
 /*
  * DATA STRUCTURE
@@ -658,6 +659,7 @@ regcache_raw_write (struct regcache *regcache, int regnum,
   old_chain = save_inferior_ptid ();
   inferior_ptid = regcache->ptid;
 
+  record_regcache_raw_write_regnum = regnum;
   target_prepare_to_store (regcache);
   memcpy (register_buffer (regcache, regnum), buf,
 	  regcache->descr->sizeof_register[regnum]);
diff --git a/gdb/target.h b/gdb/target.h
index 296781b..47b45f2 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -62,7 +62,8 @@ enum strata
     file_stratum,		/* Executable files, etc */
     core_stratum,		/* Core dump files */
     process_stratum,		/* Executing processes */
-    thread_stratum		/* Executing threads */
+    thread_stratum,		/* Executing threads */
+    record_stratum		/* Support record debugging */
   };
 
 enum thread_control_capabilities

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]