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.5 for GDB-6.8 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 the 0.1.5 is can record the memory or registers
change in command line. And if the inferior in backward part and user
want change the values of  the memory or registers, GDB will ask user
if he want destory next record and record this change or not.
Of course, not everybody like answer the questions each times. Maybe I
need add a set command in next version.
This cool idea is from GDB-patches maillist.Thank you.:)

Another change is add a command "delrecord (drec)". When the inferior
in backward part and user call this command, GDB will destorey next
recorded message and continue record message.
I think this command name is not very clear. Maybe you can help me a
new one. Thanks. :)

The first attachment is 0.1.5 diff with the GDB-6.8 record 0.1.4.
The second one is GDB record patch 0.1.5.

Example:
cat 1.c
int     a = 0;
void
cool2 ()
{
	printf ("a = %d\n", a);
}
int
cool ()
{
        a += 3;

	cool2();

        return (a);
}
int
main()
{
        int     b = 0;
        int     c = 1;

	printf ("a = %d b = %d c = %d\n", a, b, c);
        b = cool ();
	printf ("a = %d b = %d c = %d\n", a, b, c);

        c += 1;
	printf ("a = %d b = %d c = %d\n", a, b, c);
        a -= 2;
	printf ("a = %d b = %d c = %d\n", a, b, c);

        return (0);
}
gcc -g 1.c
gdb ./a.out
GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
Setting up the environment for debugging gdb.
Function "internal_error" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
Function "info_command" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
/media/disk/bgdb68/gdb/.gdbinit:8: Error in sourced command file:
No breakpoint number 0.
(gdb) b main
Breakpoint 1 at 0x80483c1: file ../../1.c, line 19.
(gdb) r
Starting program: /media/disk/bgdb68/gdb/a.out

Breakpoint 1, main () at ../../1.c:19
19              int     b = 0;
(gdb) rec
record: record and reverse function is started.
(rec) n
During symbol reading, incomplete CFI data; unspecified registers
(e.g., eax) at 0x80483be.
20              int     c = 1;
(rec)
22              printf ("a = %d b = %d c = %d\n", a, b, c);
(rec)
During symbol reading, incomplete CFI data; DW_CFA_restore unspecified
register ebp (#5) at 0xffffe411.
a = 0 b = 0 c = 1
23              b = cool ();
(rec)
a = 3
24              printf ("a = %d b = %d c = %d\n", a, b, c);
(rec)
a = 3 b = 3 c = 1
26              c += 1;
(rec) rev
record: GDB is set to reverse debug mode.
(rev) n
0x0804841a      24              printf ("a = %d b = %d c = %d\n", a, b, c);
(rev)
0x080483f8      23              b = cool ();
(rev)
0x080483ee      22              printf ("a = %d b = %d c = %d\n", a, b, c);
(rev) drec
Delete the next running messages and begin to record the running
message at current address?(y or n) y
(rev) rev
record: GDB is set to normal debug mode.
(rec) n
a = 0 b = 0 c = 1
23              b = cool ();
(rec)
a = 3
24              printf ("a = %d b = %d c = %d\n", a, b, c);
(rec)
a = 3 b = 3 c = 1
26              c += 1;
(rec) p a=9999999999
$1 = 1410065407
(rec) p a
$2 = 1410065407
(rec) n
27              printf ("a = %d b = %d c = %d\n", a, b, c);
(rec) n
a = 1410065407 b = 3 c = 2
28              a -= 2;
(rec) rev
record: GDB is set to reverse debug mode.
(rev) n
0x08048442      27              printf ("a = %d b = %d c = %d\n", a, b, c);
(rev)
26              c += 1;
(rev)
0x0804841a      24              printf ("a = %d b = %d c = %d\n", a, b, c);
(rev) p a
$3 = 3
(rev) n
0x080483f8      23              b = cool ();
(rev)
0x080483ee      22              printf ("a = %d b = %d c = %d\n", a, b, c);
(rev)
20              int     c = 1;
(rev) p a=123
Becuse GDB is not at the end of record list, it will destory the
record in the next if write memory that addr is 0x8049680 and size is
4. Do you want GDB do it?(y or [n]) y
$4 = 123
(rev) rev
record: GDB is set to normal debug mode.
(rec) n
22              printf ("a = %d b = %d c = %d\n", a, b, c);
(rec)
a = 123 b = 0 c = 1
23              b = cool ();
(rec) n
a = 126
24              printf ("a = %d b = %d c = %d\n", a, b, c);
(rec) n
a = 126 b = 126 c = 1
26              c += 1;
(rec) c
Continuing.
a = 126 b = 126 c = 2
a = 124 b = 126 c = 2
The next instruction is syscall exit_group. It will make the program
exit. Do you want to pause the program.([y] or n) y
record: record pause the program.
(rec) quit
The program is running.  Exit anyway? (y or n) y
record: record and reverse function is stopped.
Patch to make make I386-Linux GDB support Reversible Debugging
http://sourceforge.net/projects/record/
---
 Makefile.in |    4 +-
 mem-break.c |   37 ++++++++++++++++++++++++--
 record.c    |   85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 record.h    |    6 +++-
 regcache.c  |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++
 target.c    |   46 +++++++++++++++++++++++++++++++-
 6 files changed, 242 insertions(+), 9 deletions(-)

--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -2451,7 +2451,7 @@ mdebugread.o: mdebugread.c $(defs_h) $(s
 memattr.o: memattr.c $(defs_h) $(command_h) $(gdbcmd_h) $(memattr_h) \
 	$(target_h) $(value_h) $(language_h) $(vec_h) $(gdb_string_h)
 mem-break.o: mem-break.c $(defs_h) $(symtab_h) $(breakpoint_h) $(inferior_h) \
-	$(target_h)
+	$(target_h) $(record_h)
 mep-tdep.o: $(defs_h) $(frame_h) $(frame_unwind_h) $(frame_base_h) \
 	$(symtab_h) $(gdbtypes_h) $(gdbcmd_h) $(gdbcore_h) $(gdb_string_h) \
 	$(value_h) $(inferior_h) $(dis_asm_h) $(symfile_h) $(objfiles_h) \
@@ -2615,7 +2615,7 @@ p-valprint.o: p-valprint.c $(defs_h) $(g
 	$(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)
--- a/gdb/mem-break.c
+++ b/gdb/mem-break.c
@@ -29,6 +29,7 @@
 #include "breakpoint.h"
 #include "inferior.h"
 #include "target.h"
+#include "record.h"
 
 
 /* Insert a breakpoint on targets that don't have any better
@@ -80,11 +81,43 @@ default_memory_remove_breakpoint (struct
 int
 memory_insert_breakpoint (struct bp_target_info *bp_tgt)
 {
-  return gdbarch_memory_insert_breakpoint (current_gdbarch, bp_tgt);
+  int ret;
+  struct cleanup *old_cleanups = NULL;
+
+  if (gdb_is_recording)
+    {
+      old_cleanups = make_cleanup (record_not_record_cleanups, 0);
+      record_not_record = 1;
+    }
+
+  ret = gdbarch_memory_insert_breakpoint (current_gdbarch, bp_tgt);
+
+  if (gdb_is_recording)
+    {
+      do_cleanups (old_cleanups);
+    }
+
+  return ret;
 }
 
 int
 memory_remove_breakpoint (struct bp_target_info *bp_tgt)
 {
-  return gdbarch_memory_remove_breakpoint (current_gdbarch, bp_tgt);
+  int ret;
+  struct cleanup *old_cleanups = NULL;
+
+  if (gdb_is_recording)
+    {
+      old_cleanups = make_cleanup (record_not_record_cleanups, 0);
+      record_not_record = 1;
+    }
+
+  ret = gdbarch_memory_remove_breakpoint (current_gdbarch, bp_tgt);
+
+  if (gdb_is_recording)
+    {
+      do_cleanups (old_cleanups);
+    }
+
+  return ret;
 }
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -1,4 +1,4 @@
-/* Record v0.1.2 for GDB, the GNU debugger.
+/* Record v0.1.5 for GDB, the GNU debugger.
    Written by Hui Zhu <teawater@gmail.com>
 
    This file is part of GDB.
@@ -51,6 +51,7 @@ int debug_record = 0;
 int record_wait_step = 0;
 int record_delay_slot = 0;
 int record_resume_step = 0;
+int record_not_record = 0;
 static sigset_t record_maskall;
 static int record_get_sig = 0;
 struct regcache *record_regcache;
@@ -63,7 +64,7 @@ show_debug_record (struct ui_file *file,
   fprintf_filtered (file, _("Record debugging is %s.\n"), value);
 }
 
-static void
+void
 record_list_release (record_t * rec)
 {
   record_t *tmp;
@@ -92,6 +93,27 @@ record_list_release (record_t * rec)
     }
 }
 
+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;
+    }
+}
+
 /* 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
@@ -240,6 +262,13 @@ record_arch_list_add_end (int need_dasm)
   return (0);
 }
 
+/* Things to clean up if we QUIT out of function that set record_not_record.  */
+void
+record_not_record_cleanups (void *ignore)
+{
+  record_not_record = 0;
+}
+
 static void
 record_sig_handler (int signo)
 {
@@ -267,6 +296,7 @@ record_wait (struct gdbarch *gdbarch, pt
   int insn_end = 0;
   int need_dasm = 0;
   struct regcache *regcache = get_current_regcache ();
+  struct cleanup *old_cleanups = make_cleanup (record_not_record_cleanups, 0);
 
   if (debug_record)
     {
@@ -274,6 +304,7 @@ record_wait (struct gdbarch *gdbarch, pt
 			  record_wait_step);
     }
 
+  record_not_record = 1;
   record_get_sig = 0;
   act.sa_handler = record_sig_handler;
   act.sa_mask = record_maskall;
@@ -460,6 +491,8 @@ record_wait (struct gdbarch *gdbarch, pt
       status->value.sig = TARGET_SIGNAL_TRAP;
     }
 
+  do_cleanups (old_cleanups);
+
   return (inferior_ptid);
 }
 
@@ -509,6 +542,44 @@ cmd_record_start (char *args, int from_t
 }
 
 static void
+cmd_record_delete (char *args, int from_tty)
+{
+  /* check exec */
+  if (!target_has_execution)
+    {
+      error (_("record: the program is not being run."));
+    }
+
+  if (!gdbarch_record_p (current_gdbarch))
+    {
+      error (_("record: the current gdbarch don't support record function."));
+    }
+
+  if (gdb_is_recording)
+    {
+      if (record_list && record_list->next)
+	{
+	  if (!from_tty || query (_
+				  ("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 and reverse function is not started.\n"));
+    }
+}
+
+static void
 cmd_record_stop (char *args, int from_tty)
 {
   /* check exec */
@@ -524,7 +595,11 @@ cmd_record_stop (char *args, int from_tt
 
   if (gdb_is_recording)
     {
-      record_close ();
+      if (!record_list || !from_tty || query (_
+					      ("Delete all the record messages and stop record function?")))
+	{
+	  record_close ();
+	}
     }
   else
     {
@@ -573,6 +648,10 @@ _initialize_record (void)
   add_com ("record", class_obscure, cmd_record_start,
 	   _("Start the record and reverse function."));
   add_com_alias ("rec", "record", class_obscure, 1);
+  add_com ("delrecord", class_obscure, cmd_record_delete,
+	   _
+	   ("When GDB not at the end of record_list, Delete the next running messages and begin to record the running message at current address."));
+  add_com_alias ("drec", "delrecord", class_obscure, 1);
   add_com ("stoprecord", class_obscure, cmd_record_stop,
 	   _("Stop the record and reverse function."));
   add_com_alias ("srec", "stoprecord", class_obscure, 1);
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -1,4 +1,4 @@
-/* Record v0.1.2 for GDB, the GNU debugger.
+/* Record v0.1.5 for GDB, the GNU debugger.
    Written by Hui Zhu <teawater@gmail.com>
 
    This file is part of GDB.
@@ -71,12 +71,16 @@ extern int debug_record;
 extern int record_wait_step;
 extern int record_delay_slot;
 extern int record_resume_step;
+extern int record_not_record;
 extern struct regcache *record_regcache;
 
+extern void record_list_release (record_t * rec);
+extern void record_list_release_next (record_t * rec);
 extern void record_message (struct gdbarch *gdbarch);
 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_not_record_cleanups (void *ignore);
 extern ptid_t record_wait (struct gdbarch *gdbarch, ptid_t ptid, struct target_waitstatus *status);
 extern void record_close (void);
 #endif /* _RECORD_H_ */
--- 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
@@ -648,6 +649,78 @@ regcache_raw_write (struct regcache *reg
   if (gdbarch_cannot_store_register (get_regcache_arch (regcache), regnum))
     return;
 
+  /* Check for record */
+  if (gdb_is_recording && !record_not_record)
+    {
+      if (record_list && record_list->next)
+	{
+	  /* Not at the end of record list */
+	  /* Let user choice if he want to write memory or not. */
+	  if (regnum < 0)
+	    {
+	      if (!nquery (_
+			   ("Becuse GDB is not at the end of record list, it will destory the record in the next if set the values of all the registers. Do you want GDB do it?")))
+		{
+		  error (_("record: record pause the operation."));
+		}
+	    }
+	  else
+	    {
+	      if (!nquery (_
+			   ("Becuse GDB is not at the end of record list, it 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), regnum)))
+		{
+		  error (_("record: record pause the operation."));
+		}
+	    }
+
+	  /* Destory the record in the next */
+	  record_list_release_next (record_list);
+	}
+
+      /* Record to list as an instruction */
+      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."));
+	}
+      if (record_list)
+	{
+	  record_list->next = record_arch_list_head;
+	  record_arch_list_head->prev = record_list;
+	  record_list = record_arch_list_tail;
+	}
+      else
+	{
+	  record_list = record_arch_list_tail;
+	}
+    }
+
   /* If we have a valid copy of the register, and new value == old
      value, then don't bother doing the actual store. */
   if (regcache_valid_p (regcache, regnum)
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -1191,8 +1191,52 @@ target_read_memory (CORE_ADDR memaddr, g
 }
 
 int
-target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+target_write_memory (CORE_ADDR memaddr, const gdb_byte * myaddr, int len)
 {
+  /* Check for record */
+  if (gdb_is_recording && !record_not_record)
+    {
+      if (record_list && record_list->next)
+	{
+	  /* Not at the end of record list */
+	  /* Let user choice if he want to write memory or not. */
+	  if (!nquery (_
+		       ("Becuse GDB is not at the end of record list, it will destory the record in the next if write memory that addr is 0x%s and size is %d. Do you want GDB do it?"),
+		       paddr_nz (memaddr), len))
+	    {
+	      return EPERM;
+	    }
+
+	  /* Destory the record in the next */
+	  record_list_release_next (record_list);
+	}
+
+      /* Record 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 (memaddr, len))
+	{
+	  record_list_release (record_arch_list_tail);
+	  return EIO;
+	}
+      if (record_arch_list_add_end (0))
+	{
+	  record_list_release (record_arch_list_tail);
+	  return EIO;
+	}
+      if (record_list)
+	{
+	  record_list->next = record_arch_list_head;
+	  record_arch_list_head->prev = record_list;
+	  record_list = record_arch_list_tail;
+	}
+      else
+	{
+	  record_list = record_arch_list_tail;
+	}
+    }
+
   if (target_write (&current_target, TARGET_OBJECT_MEMORY, NULL,
 		    myaddr, memaddr, len) == len)
     return 0;
Patch to make make I386-Linux GDB support Reversible Debugging
http://sourceforge.net/projects/record/
---
 Makefile.in       |   28 
 gdbarch.c         |   46 
 gdbarch.h         |   13 
 i386-linux-tdep.c | 2533 +++++++++++++++++++++++++++++++++++++++++++++++++
 i386-tdep.c       | 2766 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 i386-tdep.h       |    3 
 infcmd.c          |   47 
 inferior.h        |    6 
 infrun.c          |  124 ++
 linux-nat.c       |   96 +
 mem-break.c       |   37 
 mips-tdep.c       |  734 ++++++++++++++
 record.c          |  661 ++++++++++++
 record.h          |   86 +
 regcache.c        |   73 +
 target.c          |   61 +
 target.h          |    3 
 17 files changed, 7174 insertions(+), 143 deletions(-)

--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -230,6 +230,8 @@ struct gdbarch
   gdbarch_core_read_description_ftype *core_read_description;
   gdbarch_static_transform_name_ftype *static_transform_name;
   int sofun_address_maybe_missing;
+  gdbarch_record_ftype *record;
+  gdbarch_record_dasm_ftype *record_dasm;
 };
 
 
@@ -352,6 +354,8 @@ struct gdbarch startup_gdbarch =
   0,  /* core_read_description */
   0,  /* static_transform_name */
   0,  /* sofun_address_maybe_missing */
+  NULL,  /* record_ftype */
+  NULL,  /* record_dasm_ftype */
   /* startup_gdbarch() */
 };
 
@@ -3391,6 +3395,48 @@ deprecated_current_gdbarch_select_hack (
   reinit_frame_cache ();
 }
 
+
+int
+gdbarch_record_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return (gdbarch->record != NULL);
+}
+
+int
+gdbarch_record (struct gdbarch *gdbarch)
+{
+  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));
+}
+
+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
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -900,4 +900,17 @@ extern int gdbarch_debug;
 
 extern void gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file);
 
+
+extern int gdbarch_record_p (struct gdbarch *gdbarch);
+typedef int (gdbarch_record_ftype) (struct gdbarch *gdbarch);
+extern int gdbarch_record (struct gdbarch *gdbarch);
+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);
+
+
 #endif
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -35,6 +35,9 @@
 #include "solib-svr4.h"
 #include "symtab.h"
 
+#include "record.h"
+#include <stdint.h>
+
 /* Return the name of register REG.  */
 
 static const char *
@@ -335,6 +338,2533 @@ i386_linux_write_pc (struct regcache *re
      restarted.  */
   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
@@ -429,6 +2959,9 @@ i386_linux_init_abi (struct gdbarch_info
   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);
--- 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[] =
@@ -2315,154 +2318,2679 @@ i386_fetch_pointer_argument (struct fram
   return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
 }
 
-
-static struct gdbarch *
-i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
-{
-  struct gdbarch_tdep *tdep;
-  struct gdbarch *gdbarch;
 
-  /* If there is already a candidate, use it.  */
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
+#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,
+};
 
-  /* Allocate space for the new architecture.  */
-  tdep = XCALLOC (1, struct gdbarch_tdep);
-  gdbarch = gdbarch_alloc (&info, tdep);
+/* i386 arith/logic operations */
+enum
+{
+  OP_ADDL,
+  OP_ORL,
+  OP_ADCL,
+  OP_SBBL,
+  OP_ANDL,
+  OP_SUBL,
+  OP_XORL,
+  OP_CMPL,
+};
 
-  /* General-purpose registers.  */
-  tdep->gregset = NULL;
-  tdep->gregset_reg_offset = NULL;
-  tdep->gregset_num_regs = I386_NUM_GREGS;
-  tdep->sizeof_gregset = 0;
+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;
 
-  /* Floating-point registers.  */
-  tdep->fpregset = NULL;
-  tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+/* 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;
 
-  /* The default settings include the FPU registers, the MMX registers
-     and the SSE registers.  This can be overridden for a specific ABI
-     by adjusting the members `st0_regnum', `mm0_regnum' and
-     `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
-     will show up in the output of "info all-registers".  Ideally we
-     should try to autodetect whether they are available, such that we
-     can prevent "info all-registers" from displaying registers that
-     aren't available.
+  return (0);
+}
 
-     NOTE: kevinb/2003-07-13: ... if it's a choice between printing
-     [the SSE registers] always (even when they don't exist) or never
-     showing them to the user (even when they do exist), I prefer the
-     former over the latter.  */
+/* 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;
 
-  tdep->st0_regnum = I386_ST0_REGNUM;
+      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);
+	}
 
-  /* The MMX registers are implemented as pseudo-registers.  Put off
-     calculating the register number for %mm0 until we know the number
-     of raw registers.  */
-  tdep->mm0_regnum = 0;
+      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;
+	}
 
-  /* I386_NUM_XREGS includes %mxcsr, so substract one.  */
-  tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+      if (base != 0xff)
+	{
+	  regcache_raw_read (record_regcache, base, (gdb_byte *) & tmpu32);
+	  *addr += tmpu32;
+	}
 
-  tdep->jb_pc_offset = -1;
-  tdep->struct_return = pcc_struct_return;
-  tdep->sigtramp_start = 0;
-  tdep->sigtramp_end = 0;
-  tdep->sigtramp_p = i386_sigtramp_p;
-  tdep->sigcontext_addr = NULL;
-  tdep->sc_reg_offset = NULL;
-  tdep->sc_pc_offset = -1;
-  tdep->sc_sp_offset = -1;
+      /* 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;
+	}
 
-  /* The format used for `long double' on almost all i386 targets is
-     the i387 extended floating-point format.  In fact, of all targets
-     in the GCC 2.95 tree, only OSF/1 does it different, and insists
-     on having a `long double' that's not `long' at all.  */
-  set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext);
+      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;
+    }
 
-  /* Although the i387 extended floating-point has only 80 significant
-     bits, a `long double' actually takes up 96, probably to enforce
-     alignment.  */
-  set_gdbarch_long_double_bit (gdbarch, 96);
+no_rm:
+  return (0);
+}
 
-  /* The default ABI includes general-purpose registers, 
-     floating-point registers, and the SSE registers.  */
-  set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
-  set_gdbarch_register_name (gdbarch, i386_register_name);
-  set_gdbarch_register_type (gdbarch, i386_register_type);
+/* 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;
 
-  /* Register numbers of various important registers.  */
-  set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
-  set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
-  set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
-  set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+  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);
+    }
 
-  /* NOTE: kettenis/20040418: GCC does have two possible register
-     numbering schemes on the i386: dbx and SVR4.  These schemes
-     differ in how they number %ebp, %esp, %eflags, and the
-     floating-point registers, and are implemented by the arrays
-     dbx_register_map[] and svr4_dbx_register_map in
-     gcc/config/i386.c.  GCC also defines a third numbering scheme in
-     gcc/config/i386.c, which it designates as the "default" register
-     map used in 64bit mode.  This last register numbering scheme is
-     implemented in dbx64_register_map, and is used for AMD64; see
-     amd64-tdep.c.
+  if (i386_record_lea_modrm_addr (&addr))
+    {
+      return (-1);
+    }
 
-     Currently, each GCC i386 target always uses the same register
-     numbering scheme across all its supported debugging formats
-     i.e. SDB (COFF), stabs and DWARF 2.  This is because
-     gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
-     DBX_REGISTER_NUMBER macro which is defined by each target's
-     respective config header in a manner independent of the requested
-     output debugging format.
+  if (record_arch_list_add_mem (addr, 1 << ot))
+    {
+      return (-1);
+    }
 
-     This does not match the arrangement below, which presumes that
-     the SDB and stabs numbering schemes differ from the DWARF and
-     DWARF 2 ones.  The reason for this arrangement is that it is
-     likely to get the numbering scheme for the target's
-     default/native debug format right.  For targets where GCC is the
-     native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
-     targets where the native toolchain uses a different numbering
-     scheme for a particular debug format (stabs-in-ELF on Solaris)
-     the defaults below will have to be overridden, like
-     i386_elf_init_abi() does.  */
+  return (0);
+}
 
-  /* Use the dbx register numbering scheme for stabs and COFF.  */
-  set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
-  set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+/* 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)
+{
+  int prefixes = 0;
+  uint8_t tmpu8;
+  uint16_t tmpu16;
+  uint32_t tmpu32;
+  uint32_t opcode;
 
-  /* Use the SVR4 register numbering scheme for DWARF and DWARF 2.  */
-  set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
-  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+  i386_record_pc = read_pc ();
+  aflag = 1;
+  dflag = 1;
+  override = 0;
 
-  /* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
-     be in use on any of the supported i386 targets.  */
+  if (debug_record)
+    {
+      fprintf_unfiltered (gdb_stdlog, "record: i386_record pc = 0x%s\n",
+			  paddr_nz (i386_record_pc));
+    }
 
-  set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
+  /* 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;
+    }
 
-  set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+  /* 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;
 
-  /* Call dummy code.  */
-  set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+      /* 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;
+	    }
 
-  set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
-  set_gdbarch_register_to_value (gdbarch,  i386_register_to_value);
-  set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
+	  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;
 
-  set_gdbarch_return_value (gdbarch, i386_return_value);
+      /* GRP1 */
+    case 0x80 ... 0x83:
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
 
-  set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+      if (reg != OP_CMPL)
+	{
+	  if ((opcode & 1) == 0)
+	    {
+	      ot = OT_BYTE;
+	    }
+	  else
+	    {
+	      ot = dflag + OT_WORD;
+	    }
 
-  /* Stack grows downward.  */
-  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+	  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;
 
-  set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
-  set_gdbarch_decr_pc_after_break (gdbarch, 1);
+      /* 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;
 
-  set_gdbarch_frame_args_skip (gdbarch, 8);
+      /* GRP3 */
+    case 0xf6:
+    case 0xf7:
+      if ((opcode & 1) == 0)
+	{
+	  ot = OT_BYTE;
+	}
+      else
+	{
+	  ot = dflag + OT_WORD;
+	}
+      if (i386_record_modrm ())
+	{
+	  return (-1);
+	}
 
-  /* Wire in the MMX registers.  */
+      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)
+{
+  struct gdbarch_tdep *tdep;
+  struct gdbarch *gdbarch;
+
+  /* If there is already a candidate, use it.  */
+  arches = gdbarch_list_lookup_by_info (arches, &info);
+  if (arches != NULL)
+    return arches->gdbarch;
+
+  /* Allocate space for the new architecture.  */
+  tdep = XCALLOC (1, struct gdbarch_tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* General-purpose registers.  */
+  tdep->gregset = NULL;
+  tdep->gregset_reg_offset = NULL;
+  tdep->gregset_num_regs = I386_NUM_GREGS;
+  tdep->sizeof_gregset = 0;
+
+  /* Floating-point registers.  */
+  tdep->fpregset = NULL;
+  tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+
+  /* The default settings include the FPU registers, the MMX registers
+     and the SSE registers.  This can be overridden for a specific ABI
+     by adjusting the members `st0_regnum', `mm0_regnum' and
+     `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
+     will show up in the output of "info all-registers".  Ideally we
+     should try to autodetect whether they are available, such that we
+     can prevent "info all-registers" from displaying registers that
+     aren't available.
+
+     NOTE: kevinb/2003-07-13: ... if it's a choice between printing
+     [the SSE registers] always (even when they don't exist) or never
+     showing them to the user (even when they do exist), I prefer the
+     former over the latter.  */
+
+  tdep->st0_regnum = I386_ST0_REGNUM;
+
+  /* The MMX registers are implemented as pseudo-registers.  Put off
+     calculating the register number for %mm0 until we know the number
+     of raw registers.  */
+  tdep->mm0_regnum = 0;
+
+  /* I386_NUM_XREGS includes %mxcsr, so substract one.  */
+  tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+
+  tdep->jb_pc_offset = -1;
+  tdep->struct_return = pcc_struct_return;
+  tdep->sigtramp_start = 0;
+  tdep->sigtramp_end = 0;
+  tdep->sigtramp_p = i386_sigtramp_p;
+  tdep->sigcontext_addr = NULL;
+  tdep->sc_reg_offset = NULL;
+  tdep->sc_pc_offset = -1;
+  tdep->sc_sp_offset = -1;
+
+  /* The format used for `long double' on almost all i386 targets is
+     the i387 extended floating-point format.  In fact, of all targets
+     in the GCC 2.95 tree, only OSF/1 does it different, and insists
+     on having a `long double' that's not `long' at all.  */
+  set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext);
+
+  /* Although the i387 extended floating-point has only 80 significant
+     bits, a `long double' actually takes up 96, probably to enforce
+     alignment.  */
+  set_gdbarch_long_double_bit (gdbarch, 96);
+
+  /* The default ABI includes general-purpose registers, 
+     floating-point registers, and the SSE registers.  */
+  set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, i386_register_name);
+  set_gdbarch_register_type (gdbarch, i386_register_type);
+
+  /* Register numbers of various important registers.  */
+  set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
+  set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
+  set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
+  set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+
+  /* NOTE: kettenis/20040418: GCC does have two possible register
+     numbering schemes on the i386: dbx and SVR4.  These schemes
+     differ in how they number %ebp, %esp, %eflags, and the
+     floating-point registers, and are implemented by the arrays
+     dbx_register_map[] and svr4_dbx_register_map in
+     gcc/config/i386.c.  GCC also defines a third numbering scheme in
+     gcc/config/i386.c, which it designates as the "default" register
+     map used in 64bit mode.  This last register numbering scheme is
+     implemented in dbx64_register_map, and is used for AMD64; see
+     amd64-tdep.c.
+
+     Currently, each GCC i386 target always uses the same register
+     numbering scheme across all its supported debugging formats
+     i.e. SDB (COFF), stabs and DWARF 2.  This is because
+     gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
+     DBX_REGISTER_NUMBER macro which is defined by each target's
+     respective config header in a manner independent of the requested
+     output debugging format.
+
+     This does not match the arrangement below, which presumes that
+     the SDB and stabs numbering schemes differ from the DWARF and
+     DWARF 2 ones.  The reason for this arrangement is that it is
+     likely to get the numbering scheme for the target's
+     default/native debug format right.  For targets where GCC is the
+     native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
+     targets where the native toolchain uses a different numbering
+     scheme for a particular debug format (stabs-in-ELF on Solaris)
+     the defaults below will have to be overridden, like
+     i386_elf_init_abi() does.  */
+
+  /* Use the dbx register numbering scheme for stabs and COFF.  */
+  set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+  set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+
+  /* Use the SVR4 register numbering scheme for DWARF and DWARF 2.  */
+  set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+
+  /* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
+     be in use on any of the supported i386 targets.  */
+
+  set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
+
+  set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+
+  /* Call dummy code.  */
+  set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+
+  set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
+  set_gdbarch_register_to_value (gdbarch,  i386_register_to_value);
+  set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
+
+  set_gdbarch_return_value (gdbarch, i386_return_value);
+
+  set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+
+  /* Stack grows downward.  */
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
+  set_gdbarch_decr_pc_after_break (gdbarch, 1);
+
+  set_gdbarch_frame_args_skip (gdbarch, 8);
+
+  /* Wire in the MMX registers.  */
   set_gdbarch_num_pseudo_regs (gdbarch, i386_num_mmx_regs);
   set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read);
   set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
@@ -2503,6 +5031,8 @@ i386_gdbarch_init (struct gdbarch_info i
   if (tdep->mm0_regnum == 0)
     tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
 
+  set_gdbarch_record (gdbarch, i386_record);
+
   return gdbarch;
 }
 
--- 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.  */
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -49,6 +49,8 @@
 #include "target-descriptions.h"
 #include "user-regs.h"
 
+#include "record.h"
+
 /* Functions exported for general use, in inferior.h: */
 
 void all_registers_info (char *, int);
@@ -189,6 +191,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
@@ -738,6 +746,19 @@ step_1 (int skip_subroutines, int single
 	    error (_("No current frame"));
 	  step_frame_id = get_frame_id (frame);
 
+	  if (gdb_is_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);
@@ -837,6 +858,19 @@ step_once (int skip_subroutines, int sin
 	error (_("No current frame"));
       step_frame_id = get_frame_id (frame);
 
+      if (gdb_is_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);
@@ -1089,6 +1123,19 @@ until_next_command (int from_tty)
   step_over_calls = STEP_OVER_ALL;
   step_frame_id = get_frame_id (frame);
 
+  if (gdb_is_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);
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -318,6 +318,12 @@ extern CORE_ADDR step_range_end;	/* Excl
 
 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.  */
 
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -49,6 +49,12 @@
 #include "gdb_assert.h"
 #include "mi/mi-common.h"
 
+#include "record.h"
+
+/* When the record function want inferior step before call "keep_going",
+   "record_resume_need_step" will be set to 1. After that, it will be set back to 0. */
+static int record_resume_need_step = 0;
+
 /* Prototypes for local functions */
 
 static void signals_info (char *, int);
@@ -518,6 +524,25 @@ resume (int step, enum target_signal sig
     fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%d, signal=%d)\n",
 			step, sig);
 
+  if (gdb_is_recording)
+    {
+      /* If the condition is true then GDB is not really executing the inferior
+         but merely playing back the recorded states stored by the record
+	 functionality. */
+      if (record_list && (record_list->next || gdb_is_reverse))
+        {
+          discard_cleanups (old_cleanups);
+          record_wait_step = step;
+          return;
+        }
+      else
+        {
+	  record_resume_step = step;
+          step = 1;
+          record_message (current_gdbarch);
+        }
+    }
+
   /* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
 
 
@@ -1026,10 +1051,21 @@ wait_for_inferior (int treat_exec_as_sig
 
   while (1)
     {
-      if (deprecated_target_wait_hook)
-	ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
+      /* If the condition is true then GDB is not really executing the inferior
+         but merely playing back the recorded states stored by the record
+	 functionality. */
+      if (record_list && (record_list->next || gdb_is_reverse))
+	{
+	  ecs->ptid = record_wait (current_gdbarch, ecs->waiton_ptid, ecs->wp);
+	}
       else
-	ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+	{
+	  if (deprecated_target_wait_hook)
+	    ecs->ptid =
+	      deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
+	  else
+	    ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+	}
 
       if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
         {
@@ -2007,7 +2043,9 @@ handle_inferior_event (struct execution_
 	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)
+	      || gdb_is_reverse
+              || gdb_is_recording);
       else
 	{
 	  ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
@@ -2489,6 +2527,15 @@ process_event_stop_test:
 	  /* We're doing a "next", set a breakpoint at callee's return
 	     address (the address at which the caller will
 	     resume).  */
+
+	  if (gdb_is_reverse || gdb_is_recording)
+	    {
+	      record_resume_need_step = 1;
+	      keep_going (ecs);
+	      record_resume_need_step = 0;
+	      return;
+	    }
+
 	  insert_step_resume_breakpoint_at_caller (get_current_frame ());
 	  keep_going (ecs);
 	  return;
@@ -2551,6 +2598,15 @@ process_event_stop_test:
 	  return;
 	}
 
+	if ((gdb_is_reverse || gdb_is_recording)
+	    && step_over_calls == STEP_OVER_UNDEBUGGABLE)
+	  {
+	    record_resume_need_step = 1;
+	    keep_going (ecs);
+	    record_resume_need_step = 0;
+	    return;
+	  }
+
       /* Set a breakpoint at callee's return address (the address at
          which the caller will resume).  */
       insert_step_resume_breakpoint_at_caller (get_current_frame ());
@@ -2605,6 +2661,14 @@ process_event_stop_test:
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into undebuggable function\n");
 
+      if (gdb_is_reverse || gdb_is_recording)
+	{
+	  record_resume_need_step = 1;
+	  keep_going (ecs);
+	  record_resume_need_step = 0;
+	  return;
+	}
+
       /* The inferior just stepped into, or returned to, an
          undebuggable function (where there is no debugging information
          and no line number corresponding to the address where the
@@ -2654,15 +2718,58 @@ process_event_stop_test:
          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");
+
+      if ((step_over_calls == STEP_OVER_ALL && gdb_is_reverse)
+	  || gdb_is_recording)
+	{
+	  record_resume_need_step = 1;
+	  keep_going (ecs);
+	  record_resume_need_step = 0;
+	  return;
+	}
+
       stop_step = 1;
       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
       return;
     }
 
-  if ((stop_pc == ecs->sal.pc)
-      && (ecs->current_line != ecs->sal.line
-	  || ecs->current_symtab != ecs->sal.symtab))
+    if (gdb_is_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)
+	&& (gdb_is_reverse || gdb_is_recording))
+      {
+	if ((stop_pc != ecs->sal.pc && gdb_is_reverse)
+	    || (step_over_calls == STEP_OVER_ALL && gdb_is_recording))
+	  {
+	    if (debug_infrun)
+	      fprintf_unfiltered (gdb_stdlog,
+				  "infrun: maybe stepped into subroutine\n");
+	    record_resume_need_step = 1;
+	    keep_going (ecs);
+	    record_resume_need_step = 0;
+	    return;
+	  }
+      }
+
+    if (((stop_pc == ecs->sal.pc && !gdb_is_reverse)
+	 || (stop_pc >= ecs->sal.pc && stop_pc < ecs->sal.end
+	     && gdb_is_reverse)) && (ecs->current_line != ecs->sal.line
+				     || ecs->current_symtab !=
+				     ecs->sal.symtab))
     {
       /* We are at the start of a different line.  So stop.  Note that
          we don't stop if we step into the middle of a different line.
@@ -2670,6 +2777,7 @@ process_event_stop_test:
          better.  */
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n");
+
       stop_step = 1;
       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
@@ -2730,7 +2838,7 @@ currently_stepping (struct execution_con
 	   && ((step_range_end && step_resume_breakpoint == NULL)
 	       || stepping_over_breakpoint))
 	  || ecs->stepping_through_solib_after_catch
-	  || bpstat_should_step ());
+	  || bpstat_should_step () || record_resume_need_step);
 }
 
 /* Subroutine call with source code we should not step over.  Do step
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -47,6 +47,8 @@
 #include "gdb_stat.h"		/* for struct stat */
 #include <fcntl.h>		/* for O_RDONLY */
 
+#include "record.h"
+
 #ifndef O_LARGEFILE
 #define O_LARGEFILE 0
 #endif
@@ -198,6 +200,93 @@ my_waitpid (int pid, int *status, int fl
   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 = read_pc_pid (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,
@@ -2022,7 +2111,12 @@ retry:
     {
       pid_t lwpid;
 
-      lwpid = my_waitpid (pid, &status, options);
+	if (gdb_is_recording && !record_resume_step) {
+		lwpid = my_waitpid_record (pid, &status, options);
+	}
+	else {
+		lwpid = my_waitpid (pid, &status, options);
+	}
       if (lwpid > 0)
 	{
 	  gdb_assert (pid == -1 || lwpid == pid);
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -633,7 +633,8 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
 	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
 
@@ -910,6 +911,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
@@ -1072,7 +1074,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
 	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
 
@@ -2228,7 +2231,8 @@ i386-linux-nat.o: i386-linux-nat.c $(def
 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)
+	$(i386_linux_tdep_h) $(glibc_tdep_h) $(solib_svr4_h) $(symtab_h) \
+	$(record_h)
 i386-nat.o: i386-nat.c $(defs_h) $(breakpoint_h) $(command_h) $(gdbcmd_h)
 i386nbsd-nat.o: i386nbsd-nat.c $(defs_h) $(gdbcore_h) $(regcache_h) \
 	$(target_h) $(i386_tdep_h) $(i386bsd_nat_h) $(nbsd_nat_h) \
@@ -2259,7 +2263,7 @@ i386-tdep.o: i386-tdep.c $(defs_h) $(arc
 	$(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) \
@@ -2290,7 +2294,7 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_strin
 	$(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)
+	$(user_regs_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)
 inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
@@ -2304,7 +2308,7 @@ infrun.o: infrun.c $(defs_h) $(gdb_strin
 	$(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)
@@ -2349,7 +2353,7 @@ linux-nat.o: linux-nat.c $(defs_h) $(inf
 	$(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)
+	$(linux_fork_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) \
@@ -2447,7 +2451,7 @@ mdebugread.o: mdebugread.c $(defs_h) $(s
 memattr.o: memattr.c $(defs_h) $(command_h) $(gdbcmd_h) $(memattr_h) \
 	$(target_h) $(value_h) $(language_h) $(vec_h) $(gdb_string_h)
 mem-break.o: mem-break.c $(defs_h) $(symtab_h) $(breakpoint_h) $(inferior_h) \
-	$(target_h)
+	$(target_h) $(record_h)
 mep-tdep.o: $(defs_h) $(frame_h) $(frame_unwind_h) $(frame_base_h) \
 	$(symtab_h) $(gdbtypes_h) $(gdbcmd_h) $(gdbcore_h) $(gdb_string_h) \
 	$(value_h) $(inferior_h) $(dis_asm_h) $(symfile_h) $(objfiles_h) \
@@ -2494,7 +2498,7 @@ mips-tdep.o: mips-tdep.c $(defs_h) $(gdb
 	$(elf_bfd_h) $(symcat_h) $(sim_regno_h) $(dis_asm_h) \
 	$(frame_unwind_h) $(frame_base_h) $(trad_frame_h) $(infcall_h) \
 	$(floatformat_h) $(remote_h) $(target_descriptions_h) \
-	$(dwarf2_frame_h) $(user_regs_h)
+	$(dwarf2_frame_h) $(user_regs_h) $(record_h)
 memory-map.o: memory-map.c $(defs_h) $(memory_map_h) $(xml_support_h) \
 	$(gdb_assert_h) $(exceptions_h) $(gdb_string_h)
 mn10300-linux-tdep.o: mn10300-linux-tdep.c $(defs_h) $(gdbcore_h) \
@@ -2611,7 +2615,7 @@ p-valprint.o: p-valprint.c $(defs_h) $(g
 	$(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)
@@ -2871,7 +2875,7 @@ symtab.o: symtab.c $(defs_h) $(symtab_h)
 target.o: target.c $(defs_h) $(gdb_string_h) $(target_h) $(gdbcmd_h) \
 	$(symtab_h) $(inferior_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
 	$(gdb_wait_h) $(dcache_h) $(regcache_h) $(gdb_assert_h) $(gdbcore_h) \
-	$(exceptions_h) $(target_descriptions_h)
+	$(exceptions_h) $(target_descriptions_h) $(record_h)
 target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \
 	$(target_h) $(target_descriptions_h) $(vec_h) $(xml_tdesc_h) \
 	$(gdbcmd_h) $(gdb_assert_h) $(gdbtypes_h) $(reggroups_h) \
@@ -2991,6 +2995,8 @@ xtensa-tdep.o: xtensa-tdep.c $(defs_h) $
 	$(reggroups_h) $(arch_utils_h) $(osabi_h) $(block_h) $(gdb_assert_h) \
 	$(elf_bfd_h) $(xtensa_tdep_h) $(dwarf2_frame_h)
 xtensa-config.o: $(defs_h) $(xtensa_tdep_h)
+record.o: record.c $(defs_h) $(inferior_h) $(gdbcmd_h) $(regcache_h) \
+	$(top_h) $(record_h)
 
 #
 # gdb/cli/ dependencies
--- a/gdb/mem-break.c
+++ b/gdb/mem-break.c
@@ -29,6 +29,7 @@
 #include "breakpoint.h"
 #include "inferior.h"
 #include "target.h"
+#include "record.h"
 
 
 /* Insert a breakpoint on targets that don't have any better
@@ -80,11 +81,43 @@ default_memory_remove_breakpoint (struct
 int
 memory_insert_breakpoint (struct bp_target_info *bp_tgt)
 {
-  return gdbarch_memory_insert_breakpoint (current_gdbarch, bp_tgt);
+  int ret;
+  struct cleanup *old_cleanups = NULL;
+
+  if (gdb_is_recording)
+    {
+      old_cleanups = make_cleanup (record_not_record_cleanups, 0);
+      record_not_record = 1;
+    }
+
+  ret = gdbarch_memory_insert_breakpoint (current_gdbarch, bp_tgt);
+
+  if (gdb_is_recording)
+    {
+      do_cleanups (old_cleanups);
+    }
+
+  return ret;
 }
 
 int
 memory_remove_breakpoint (struct bp_target_info *bp_tgt)
 {
-  return gdbarch_memory_remove_breakpoint (current_gdbarch, bp_tgt);
+  int ret;
+  struct cleanup *old_cleanups = NULL;
+
+  if (gdb_is_recording)
+    {
+      old_cleanups = make_cleanup (record_not_record_cleanups, 0);
+      record_not_record = 1;
+    }
+
+  ret = gdbarch_memory_remove_breakpoint (current_gdbarch, bp_tgt);
+
+  if (gdb_is_recording)
+    {
+      do_cleanups (old_cleanups);
+    }
+
+  return ret;
 }
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -58,6 +58,9 @@
 #include "dwarf2-frame.h"
 #include "user-regs.h"
 
+#include "record.h"
+#include <stdint.h>
+
 static const struct objfile_data *mips_pdr_data;
 
 static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum);
@@ -5213,6 +5216,734 @@ value_of_mips_user_reg (struct frame_inf
   return value_of_register (*reg_p, frame);
 }
 
+/* When "record_delay_slot" is true (mean that the prev instruction has delay
+   slot), GDB  need to deal with instrction in the delay slot that address is
+   "mips_delay_slot_addr" and the instruction in target of delay slot
+   instruction that address is "mips_target_addr". */
+static CORE_ADDR mips_delay_slot_addr;
+static CORE_ADDR mips_target_addr;
+
+/* Record the value of the memory that willbe changed in current 32 bits instruction
+   to "record_arch_list".
+   Return -1 if something wrong. */
+static int
+mips_record_32 (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  uint32_t insn = (uint32_t) mips_fetch_instruction (pc);
+  uint32_t opcode;
+  const struct mips_regnum *regnum = mips_regnum (gdbarch);
+  int add_pc = 1;
+  uint32_t tmpu32;
+
+  if (debug_record)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+			  "record: mips_record_32 insn = 0x%08x\n",
+			  (unsigned int) insn);
+    }
+
+  opcode = insn >> 26;
+  switch (opcode)
+    {
+    case 0x00:
+      switch ((insn >> 0) & 0x3f)
+	{
+	  /* sll */
+	case 0x00:
+	  /* srl */
+	case 0x02:
+	  /* sra */
+	case 0x03:
+	  /* sllv */
+	case 0x04:
+	  /* srlv */
+	case 0x06:
+	  /* srav */
+	case 0x07:
+	  /* movz */
+	case 0x0a:
+	  /* movn */
+	case 0x0b:
+	  /* mfhi */
+	case 0x10:
+	  /* mflo */
+	case 0x12:
+	  /* add */
+	case 0x20:
+	  /* addu */
+	case 0x21:
+	  /* sub */
+	case 0x22:
+	  /* subu */
+	case 0x23:
+	  /* and */
+	case 0x24:
+	  /* or */
+	case 0x25:
+	  /* xor */
+	case 0x26:
+	  /* nor */
+	case 0x27:
+	  /* slt */
+	case 0x2a:
+	  /* sltu */
+	case 0x2b:
+	  goto set_rd;
+	  break;
+	  /* jr */
+	case 0x08:
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & mips_target_addr);
+	  goto set_delay_slot_pc;
+	  break;
+	  /* jalr */
+	case 0x09:
+	  {
+	    uint32_t rd = (insn >> 11) & 0x1f;
+	    if (rd != 0)
+	      {
+		if (record_arch_list_add_reg (rd))
+		  {
+		    return (-1);
+		  }
+	      }
+	    regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			       (gdb_byte *) & mips_target_addr);
+	    goto set_delay_slot_pc;
+	  }
+	  break;
+	  /* sync */
+	case 0x0f:
+	  break;
+	  /* mthi */
+	case 0x11:
+	  if (record_arch_list_add_reg (regnum->hi))
+	    {
+	      return (-1);
+	    }
+	  break;
+	  /* mtlo */
+	case 0x13:
+	  if (record_arch_list_add_reg (regnum->lo))
+	    {
+	      return (-1);
+	    }
+	  break;
+	  /* mult */
+	case 0x18:
+	  /* multu */
+	case 0x19:
+	  /* div */
+	case 0x1a:
+	  /* divu */
+	case 0x1b:
+	  goto set_hi_lo;
+	  break;
+	default:
+	  goto no_support;
+	  break;
+	}
+      break;
+
+    case 0x01:
+      switch ((insn >> 16) & 0x1f)
+	{
+	  /* bltz */
+	case 0x00:
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 < 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  break;
+	  /* bgez */
+	case 0x01:
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 >= 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  break;
+	  /* bltzl */
+	case 0x02:
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 < 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  else
+	    {
+	      goto set_pc;
+	    }
+	  break;
+	  /* bgezl */
+	case 0x03:
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 >= 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  else
+	    {
+	      goto set_pc;
+	    }
+	  break;
+	  /* bltzal */
+	case 0x10:
+	  if (record_arch_list_add_reg (31))
+	    {
+	      return (-1);
+	    }
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 < 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  break;
+	  /* bgezal */
+	case 0x11:
+	  if (record_arch_list_add_reg (31))
+	    {
+	      return (-1);
+	    }
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 >= 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  break;
+	  /* bltzall */
+	case 0x12:
+	  if (record_arch_list_add_reg (31))
+	    {
+	      return (-1);
+	    }
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 < 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  else
+	    {
+	      goto set_pc;
+	    }
+	  break;
+	  /* bgezall */
+	case 0x13:
+	  if (record_arch_list_add_reg (31))
+	    {
+	      return (-1);
+	    }
+	  regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			     (gdb_byte *) & tmpu32);
+	  if (tmpu32 >= 0)
+	    {
+	      goto set_imm_delay_slot_pc;
+	    }
+	  else
+	    {
+	      goto set_pc;
+	    }
+	  break;
+	default:
+	  goto no_support;
+	  break;
+	}
+      break;
+
+      /* j */
+    case 0x02:
+      mips_target_addr =
+	(pc & 0xf0000000) | (((insn >> 0) & 0x03ffffff) << 2);
+      goto set_delay_slot_pc;
+      break;
+
+      /* beq */
+    case 0x04:
+      {
+	uint32_t tmp;
+	regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	  (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+	  (gdb_byte *) & tmp);
+	if (tmpu32 == tmp)
+	  {
+	    goto set_imm_delay_slot_pc;
+	  }
+      }
+      break;
+
+      /* bne */
+    case 0x05:
+      {
+	uint32_t tmp;
+	regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	  (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+	  (gdb_byte *) & tmp);
+	if (tmpu32 != tmp)
+	  {
+	    goto set_imm_delay_slot_pc;
+	  }
+      }
+      break;
+
+      /* blez */
+    case 0x06:
+      regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	(gdb_byte *) & tmpu32);
+      if (tmpu32 <= 0)
+	{
+	  goto set_imm_delay_slot_pc;
+	}
+      break;
+
+      /* bgtz */
+    case 0x07:
+      regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	(gdb_byte *) & tmpu32);
+      if (tmpu32 > 0)
+	{
+	  goto set_imm_delay_slot_pc;
+	}
+      break;
+
+      /* beql */
+    case 0x14:
+      {
+	uint32_t tmp;
+	regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	  (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+	  (gdb_byte *) & tmp);
+	if (tmpu32 == tmp)
+	  {
+	    goto set_imm_delay_slot_pc;
+	  }
+	else
+	  {
+	    goto set_pc;
+	  }
+      }
+      break;
+
+      /* bnel */
+    case 0x15:
+      {
+	uint32_t tmp;
+	regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	  (gdb_byte *) & tmpu32);
+	regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+	  (gdb_byte *) & tmp);
+	if (tmpu32 == tmp)
+	  {
+	    goto set_imm_delay_slot_pc;
+	  }
+	else
+	  {
+	    goto set_pc;
+	  }
+      }
+      break;
+
+      /* blezl */
+    case 0x16:
+      regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	(gdb_byte *) & tmpu32);
+      if (tmpu32 <= 0)
+	{
+	  goto set_imm_delay_slot_pc;
+	}
+      else
+	{
+	  goto set_pc;
+	}
+      break;
+
+      /* bgtzl */
+    case 0x17:
+      regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+	(gdb_byte *) & tmpu32);
+      if (tmpu32 > 0)
+	{
+	  goto set_imm_delay_slot_pc;
+	}
+      else
+	{
+	  goto set_pc;
+	}
+      break;
+
+      /* jal */
+    case 0x03:
+      if (record_arch_list_add_reg (31))
+	{
+	  return (-1);
+	}
+      mips_target_addr =
+	(pc & 0xf0000000) | (((insn >> 0) & 0x03ffffff) << 2);
+      goto set_delay_slot_pc;
+      break;
+
+      /* jalx */
+    case 0x1d:
+      goto no_support;
+      break;
+
+      /* addi */
+    case 0x08:
+      /* addiu */
+    case 0x09:
+      /* slti */
+    case 0x0a:
+      /* sltiu */
+    case 0x0b:
+      /* andi */
+    case 0x0c:
+      /* ori */
+    case 0x0d:
+      /* xori */
+    case 0x0e:
+      /* lui */
+    case 0x0f:
+      goto set_rt;
+      break;
+
+      /* COP0 */
+    case 0x10:
+      if ((insn >> 25) & 0x1)
+	{
+	  switch ((insn >> 0) & 0x3f)
+	    {
+	      /* eret */
+	    case 0x18:
+	      goto set_pc;
+	      break;
+	    default:
+	      goto no_support;
+	      break;
+	    }
+	}
+      else
+	{
+	  switch ((insn >> 21) & 0x1f)
+	    {
+	      /* mfc0 */
+	    case 0x00:
+	      goto set_rt;
+	      break;
+	      /* mtc0 */
+	    case 0x04:
+	      {
+		switch ((insn >> 11) & 0x1f)
+		  {
+		  case 13:
+		    /* Cause */
+		    if (record_arch_list_add_reg (regnum->cause))
+		      {
+			return (-1);
+		      }
+		  case 8:
+		    /* badvaddr */
+		    if (record_arch_list_add_reg (regnum->badvaddr))
+		      {
+			return (-1);
+		      }
+		  }
+	      }
+	      break;
+	    default:
+	      goto no_support;
+	      break;
+	    }
+	}
+      break;
+
+    case 0x1c:
+      switch ((insn >> 0) & 0x3f)
+	{
+	  /* madd */
+	case 0x00:
+	  /* maddu */
+	case 0x01:
+	  /* msub */
+	case 0x04:
+	  /* msubu */
+	case 0x05:
+	  goto set_hi_lo;
+	  break;
+	  /* mul */
+	case 0x02:
+	  {
+	    uint32_t rd = (insn >> 11) & 0x1f;
+	    if (rd != 0)
+	      {
+		if (record_arch_list_add_reg (rd))
+		  {
+		    return (-1);
+		  }
+	      }
+	    goto set_hi_lo;
+	  }
+	  break;
+	  /* clo */
+	case 0x21:
+	  /* clz */
+	case 0x20:
+	  goto set_rd;
+	  break;
+	default:
+	  goto no_support;
+	  break;
+	}
+      break;
+
+      /* lb */
+    case 0x20:
+      /* lh */
+    case 0x21:
+      /* lwl */
+    case 0x22:
+      /* lw */
+    case 0x23:
+      /* lbu */
+    case 0x24:
+      /* lhu */
+    case 0x25:
+      /* lwr */
+    case 0x26:
+      /* ll */
+    case 0x30:
+      goto set_rt;
+      break;
+
+      /* sb */
+    case 0x28:
+      /* sh */
+    case 0x29:
+      /* swl */
+    case 0x2a:
+      /* sw */
+    case 0x2b:
+      /* swr */
+    case 0x2e:
+      /* sc */
+    case 0x38:
+      {
+	uint32_t addr;
+
+	/* addr */
+	/* base */
+	regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+			   (gdb_byte *) & addr);
+	/* offset */
+	addr += (insn >> 0) & 0xffff;
+
+	switch (opcode)
+	  {
+	    /* sb */
+	  case 0x28:
+	    if (record_arch_list_add_mem (addr, 1))
+	      {
+		return (-1);
+	      }
+	    break;
+	    /* sh */
+	  case 0x29:
+	    if (record_arch_list_add_mem (addr, 2))
+	      {
+		return (-1);
+	      }
+	    break;
+	    /* swl */
+	  case 0x2a:
+	    /* swr */
+	  case 0x2e:
+	    if (record_arch_list_add_mem (addr & 0xffffff00, 2))
+	      {
+		return (-1);
+	      }
+	    break;
+	    /* sw */
+	  case 0x2b:
+	    if (record_arch_list_add_mem (addr, 4))
+	      {
+		return (-1);
+	      }
+	    break;
+	    /* sc */
+	  case 0x38:
+	    if (record_arch_list_add_mem (addr, 4))
+	      {
+		return (-1);
+	      }
+	    goto set_rt;
+	    break;
+	  }
+      }
+      break;
+      /* pref */
+    case 0x33:
+      break;
+
+    default:
+      goto no_support;
+      break;
+    }
+
+out:
+  if (record_delay_slot)
+    {
+      if (add_pc)
+	{
+	  if (record_arch_list_add_reg (regnum->pc))
+	    {
+	      return (-1);
+	    }
+	  add_pc = 0;
+	}
+    }
+  if (record_arch_list_add_end (add_pc))
+    {
+      return (-1);
+    }
+  return (0);
+
+no_support:
+  printf_unfiltered (_
+		     ("record: record and reverse function don't support 32 bits instruction 0x%08x.\n"),
+		     (unsigned int) insn);
+  return (-1);
+
+set_rd:
+  {
+    uint32_t rd = (insn >> 11) & 0x1f;
+    if (rd != 0)
+      {
+	if (record_arch_list_add_reg (rd))
+	  {
+	    return (-1);
+	  }
+      }
+  }
+  goto out;
+
+set_rt:
+  {
+    uint32_t rt = (insn >> 16) & 0x1f;
+    if (rt != 0)
+      {
+	if (record_arch_list_add_reg (rt))
+	  {
+	    return (-1);
+	  }
+      }
+  }
+  goto out;
+
+set_imm_delay_slot_pc:
+  {
+    uint32_t imm = (insn >> 0) & 0xffff;
+    if (imm >> 15)
+      {
+	imm |= 0xffff0000;
+      }
+    imm <<= 2;
+    mips_target_addr = pc + 4 + imm;
+  }
+  goto set_delay_slot_pc;
+
+set_delay_slot_pc:
+  mips_delay_slot_addr = pc + 4;
+  record_delay_slot++;
+  goto set_pc;
+
+set_pc:
+  if (record_arch_list_add_reg (regnum->pc))
+    {
+      return (-1);
+    }
+  add_pc = 0;
+  goto out;
+
+set_hi_lo:
+  if (record_arch_list_add_reg (regnum->hi))
+    {
+      return (-1);
+    }
+  if (record_arch_list_add_reg (regnum->lo))
+    {
+      return (-1);
+    }
+  goto out;
+}
+
+/* Record the value of the memory that willbe changed in current instruction
+   to "record_arch_list".
+   Return -1 if something wrong. */
+static int mips_record (struct gdbarch *gdbarch)
+{
+  CORE_ADDR pc = read_pc ();
+
+  if (debug_record)
+    {
+      fprintf_unfiltered (gdb_stdlog, "record: mips_record pc = 0x%s\n",
+			  paddr_nz (pc));
+    }
+
+  if (mips_pc_is_mips16 (pc))
+    {
+      printf_unfiltered (_
+			 ("record: record and reverse function don't support mips16.\n"));
+      return (-1);
+    }
+
+  if (record_delay_slot)
+    {
+      if (mips_record_32 (mips_delay_slot_addr))
+	{
+	  return (-1);
+	}
+      if (mips_record_32 (mips_target_addr))
+	{
+	  return (-1);
+	}
+      record_delay_slot--;
+    }
+  return (mips_record_32 (pc));
+}
+
+static void mips_record_dasm (struct gdbarch *gdbarch)
+{
+  const struct mips_regnum *regnum;
+  ULONGEST pc;
+
+  if (mips_pc_is_mips16 (read_pc ()))
+    {
+      error (_
+	     ("record: record and reverse function don't support mips16.\n"));
+    }
+
+  regnum = mips_regnum (gdbarch);
+  regcache_cooked_read_unsigned (record_regcache, regnum->pc, &pc);
+  if (gdb_is_reverse)
+    {
+      pc -= 4;
+    }
+  else
+    {
+      pc += 4;
+    }
+  regcache_cooked_write_unsigned (record_regcache, regnum->pc, pc);
+}
+
 static struct gdbarch *
 mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
@@ -5877,6 +6608,9 @@ mips_gdbarch_init (struct gdbarch_info i
     user_reg_add (gdbarch, mips_register_aliases[i].name,
 		  value_of_mips_user_reg, &mips_register_aliases[i].regnum);
 
+  set_gdbarch_record (gdbarch, mips_record);
+  set_gdbarch_record_dasm (gdbarch, mips_record_dasm);
+
   return gdbarch;
 }
 
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -0,0 +1,661 @@
+/* Record v0.1.5 for GDB, the GNU debugger.
+   Written by Hui Zhu <teawater@gmail.com>
+
+   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/>.  */
+
+/* Before the inferior resume, if the record function is open and inferior will
+   really execute (will not call "record_wait"), the GDB will call
+   function "record_message" to record the values of registrs and memory that
+   will be changed in next instrution to "record_list".
+   When GDB is in reverse debug mode and inferior is not in the begin of 
+   "record_list" or GDB is in normail deubg mode and inferior is not in the
+   end of "record_list", GDB will call this function instead "target_wait". In
+   this status, function "resume" will directly return. Then inferior will
+   instead execute to call "record_wait".
+   "record_wait" will set the running message in "record_list" to inferior.
+   Then the registers and memory of  inferior will change back to before. */
+
+#include "defs.h"
+#include "inferior.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "top.h"
+#include "record.h"
+
+#include <signal.h>
+
+#define RECORD_REC_PROMPT	"(rec) "
+#define RECORD_REV_PROMPT	"(rev) "
+
+extern struct breakpoint *breakpoint_chain;
+
+record_t *record_list = NULL;
+record_t *record_arch_list_head = NULL;
+record_t *record_arch_list_tail = NULL;
+unsigned int gdb_is_recording = 0;
+int gdb_is_reverse = 0;
+int debug_record = 0;
+int record_wait_step = 0;
+int record_delay_slot = 0;
+int record_resume_step = 0;
+int record_not_record = 0;
+static sigset_t record_maskall;
+static int record_get_sig = 0;
+struct regcache *record_regcache;
+static char record_gdb_prompt[20];
+
+static void
+show_debug_record (struct ui_file *file, int from_tty,
+		   struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Record debugging is %s.\n"), value);
+}
+
+void
+record_list_release (record_t * rec)
+{
+  record_t *tmp;
+
+  if (!rec)
+    return;
+
+  while (rec->next)
+    {
+	rec = rec->next;
+    }
+
+  while (rec)
+    {
+      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);
+    }
+}
+
+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;
+    }
+}
+
+/* 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 ();
+
+  ret = gdbarch_record (gdbarch);
+  if (ret > 0)
+    {
+      record_list_release (record_arch_list_tail);
+      error (_("record: record pause the program."));
+    }
+  if (ret < 0)
+    {
+      record_delay_slot = 0;
+      record_list_release (record_arch_list_tail);
+      error (_("record: record message error."));
+    }
+
+  if (record_list)
+    {
+      record_list->next = record_arch_list_head;
+      record_arch_list_head->prev = record_list;
+      record_list = record_arch_list_tail;
+    }
+  else
+    {
+      record_list = record_arch_list_tail;
+    }
+}
+
+/* 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 (debug_record)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+			  "record: add reg num = %d to arch 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 (debug_record)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+			  "record: add mem addr = 0x%s len = %d to arch 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 (debug_record)
+    {
+      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);
+}
+
+/* Things to clean up if we QUIT out of function that set record_not_record.  */
+void
+record_not_record_cleanups (void *ignore)
+{
+  record_not_record = 0;
+}
+
+static void
+record_sig_handler (int signo)
+{
+  if (debug_record)
+    {
+      fprintf_unfiltered (gdb_stdlog, "record: get a signal\n");
+    }
+  record_wait_step = 1;
+  record_get_sig = 1;
+}
+
+/* When GDB is in reverse debug mode and inferior is not in the begin of 
+   "record_list" or GDB is in normail deubg mode and inferior is not in the
+   end of "record_list", GDB will call this function instead "target_wait". In
+   this status, function "resume" will directly return. Then inferior will
+   instead execute to call "record_wait".
+   "record_wait" will set the running message in "record_list" to inferior.
+   Then the registers and memory of  inferior will change back to before. */
+ptid_t
+record_wait (struct gdbarch *gdbarch, ptid_t ptid, struct target_waitstatus *status)
+{
+  struct sigaction act, old_act;
+  static int state = 0;		/* 0 normal 1 to the end 2 to the begin */
+  int con = 1;
+  int insn_end = 0;
+  int need_dasm = 0;
+  struct regcache *regcache = get_current_regcache ();
+  struct cleanup *old_cleanups = make_cleanup (record_not_record_cleanups, 0);
+
+  if (debug_record)
+    {
+      fprintf_unfiltered (gdb_stdlog, "record: record_wait step = %d\n",
+			  record_wait_step);
+    }
+
+  record_not_record = 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 (_("sigaction"));
+    }
+
+  do
+    {
+      /* check state */
+      if ((gdb_is_reverse && !record_list->prev && state == 2)
+	  || (!gdb_is_reverse && !record_list->next && state == 1))
+	{
+	  if (state == 1)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "record: running to the end of record list.\n");
+	    }
+	  else if (state == 2)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "record: running to the begin of record list.\n");
+	    }
+	  stop_soon = STOP_QUIETLY;
+	  break;
+	}
+      state = 0;
+
+      /* set register and memory according to record_list */
+      if (record_list->type == record_reg)
+	{
+	  /* reg */
+	  gdb_byte reg[MAX_REGISTER_SIZE];
+	  if (debug_record)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "record: record_list reg num = %d to arch list.\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 (debug_record)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "record: record_list mem addr = 0x%s len = %d to current.\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
+	{
+	  if (debug_record)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "record: record_list end need_dasm = %d to current.\n",
+				  record_list->u.need_dasm);
+	    }
+
+	  need_dasm = record_list->u.need_dasm;
+	  if (!gdb_is_reverse)
+	    {
+	      insn_end = 1;
+	    }
+	}
+
+      if (gdb_is_reverse)
+	{
+	  if (record_list->prev)
+	    {
+	      record_list = record_list->prev;
+	      if (!record_list->type)
+		{
+		  insn_end = 1;
+		}
+	    }
+	  else
+	    {
+	      state = 2;
+	      insn_end = 1;
+	    }
+	}
+      else
+	{
+	  if (record_list->next)
+	    {
+	      record_list = record_list->next;
+	    }
+	  else
+	    {
+	      state = 1;
+	    }
+	}
+
+      if (insn_end)
+	{
+	  struct breakpoint *b;
+	  CORE_ADDR tmp_pc;
+
+	  if (debug_record)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "record: insn end need_dasm = %d to current.\n",
+				  need_dasm);
+	    }
+
+	  if (need_dasm)
+	    {
+	      gdbarch_record_dasm (gdbarch);
+	    }
+
+	  tmp_pc = read_pc ();
+
+	  /* end */
+	  if (record_wait_step)
+	    {
+	      if (debug_record)
+		{
+		  fprintf_unfiltered (gdb_stdlog, "record: step.\n");
+		}
+	      con = 0;
+	    }
+
+	  /* check breakpoint */
+	  for (b = breakpoint_chain; b; b = b->next)
+	    {
+	      if (b->loc->inserted)
+		{
+		  if (b->loc->target_info.placed_address == tmp_pc)
+		    {
+		      if (debug_record)
+			{
+			  fprintf_unfiltered (gdb_stdlog,
+					      "record: break at 0x%s.\n",
+					      paddr_nz (tmp_pc));
+			}
+		      con = 0;
+		      break;
+		    }
+		}
+	    }
+
+	  insn_end = 0;
+	}
+    }
+  while (con);
+
+  if (sigaction (SIGALRM, &old_act, NULL))
+    {
+      perror_with_name (_("sigaction"));
+    }
+
+  status->kind = TARGET_WAITKIND_STOPPED;
+  if (record_get_sig)
+    {
+      status->value.sig = TARGET_SIGNAL_INT;
+    }
+  else
+    {
+      status->value.sig = TARGET_SIGNAL_TRAP;
+    }
+
+  do_cleanups (old_cleanups);
+
+  return (inferior_ptid);
+}
+
+void
+record_close (void)
+{
+  gdb_is_recording = 0;
+  gdb_is_reverse = 0;
+  record_list_release (record_list);
+  record_list = NULL;
+  record_delay_slot = 0;
+  set_prompt (record_gdb_prompt);
+  printf_unfiltered (_("record: record and reverse function is stopped.\n"));
+}
+
+static void
+cmd_record_start (char *args, int from_tty)
+{
+  /* check exec */
+  if (!target_has_execution)
+    {
+      error (_("record: the program is not being run."));
+    }
+
+  if (!gdbarch_record_p (current_gdbarch))
+    {
+      error (_("record: the current gdbarch don't support record function."));
+    }
+
+  if (gdb_is_recording)
+    {
+      printf_unfiltered (_
+			 ("record: record and reverse function has already been started.\n"));
+    }
+  else
+    {
+      char *tmp;
+
+      gdb_is_recording = 1;
+      printf_unfiltered (_
+			 ("record: record and reverse function is started.\n"));
+
+      tmp = get_prompt ();
+      snprintf (record_gdb_prompt, 20, "%s", tmp);
+      set_prompt (RECORD_REC_PROMPT);
+    }
+}
+
+static void
+cmd_record_delete (char *args, int from_tty)
+{
+  /* check exec */
+  if (!target_has_execution)
+    {
+      error (_("record: the program is not being run."));
+    }
+
+  if (!gdbarch_record_p (current_gdbarch))
+    {
+      error (_("record: the current gdbarch don't support record function."));
+    }
+
+  if (gdb_is_recording)
+    {
+      if (record_list && record_list->next)
+	{
+	  if (!from_tty || query (_
+				  ("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 and reverse function is not started.\n"));
+    }
+}
+
+static void
+cmd_record_stop (char *args, int from_tty)
+{
+  /* check exec */
+  if (!target_has_execution)
+    {
+      error (_("record: the program is not being run."));
+    }
+
+  if (!gdbarch_record_p (current_gdbarch))
+    {
+      error (_("record: the current gdbarch don't support record function."));
+    }
+
+  if (gdb_is_recording)
+    {
+      if (!record_list || !from_tty || query (_
+					      ("Delete all the record messages and stop record function?")))
+	{
+	  record_close ();
+	}
+    }
+  else
+    {
+      printf_unfiltered (_
+			 ("record: record and reverse function is not started.\n"));
+    }
+}
+
+static void
+cmd_reverse (char *args, int from_tty)
+{
+  if (gdb_is_reverse)
+    {
+      gdb_is_reverse = 0;
+      printf_unfiltered (_("record: GDB is set to normal debug mode.\n"));
+      set_prompt (RECORD_REC_PROMPT);
+    }
+  else
+    {
+      if (!record_list)
+	{
+	  error (_("record: record and reverse function is not started."));
+	}
+      gdb_is_reverse = 1;
+      printf_unfiltered (_("record: GDB is set to reverse debug mode.\n"));
+      set_prompt (RECORD_REV_PROMPT);
+    }
+}
+
+void
+_initialize_record (void)
+{
+  /*  init record_maskall */
+  if (sigfillset (&record_maskall) == -1)
+    {
+      perror_with_name (_("sigfillset"));
+    }
+
+  add_setshow_zinteger_cmd ("record", class_maintenance, &debug_record,
+			    _("Set record debugging."),
+			    _("Show record debugging."),
+			    _
+			    ("When non-zero, record specific debugging is enabled."),
+			    NULL, show_debug_record, &setdebuglist,
+			    &showdebuglist);
+  add_com ("record", class_obscure, cmd_record_start,
+	   _("Start the record and reverse function."));
+  add_com_alias ("rec", "record", class_obscure, 1);
+  add_com ("delrecord", class_obscure, cmd_record_delete,
+	   _
+	   ("When GDB not at the end of record_list, Delete the next running messages and begin to record the running message at current address."));
+  add_com_alias ("drec", "delrecord", class_obscure, 1);
+  add_com ("stoprecord", class_obscure, cmd_record_stop,
+	   _("Stop the record and reverse function."));
+  add_com_alias ("srec", "stoprecord", class_obscure, 1);
+  add_com ("reverse", class_obscure, cmd_reverse,
+	   _("Set GDB to the reverse debug mode or the normal debug mode."));
+  add_com_alias ("rev", "reverse", class_obscure, 1);
+}
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -0,0 +1,86 @@
+/* Record v0.1.5 for GDB, the GNU debugger.
+   Written by Hui Zhu <teawater@gmail.com>
+
+   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_
+
+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 record_t *record_list;
+extern record_t *record_arch_list_head;
+extern record_t *record_arch_list_tail;
+extern int record_arch_need_dasm;
+extern unsigned int gdb_is_recording;
+extern int gdb_is_reverse;
+extern int debug_record;
+extern int record_wait_step;
+extern int record_delay_slot;
+extern int record_resume_step;
+extern int record_not_record;
+extern struct regcache *record_regcache;
+
+extern void record_list_release (record_t * rec);
+extern void record_list_release_next (record_t * rec);
+extern void record_message (struct gdbarch *gdbarch);
+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_not_record_cleanups (void *ignore);
+extern ptid_t record_wait (struct gdbarch *gdbarch, ptid_t ptid, struct target_waitstatus *status);
+extern void record_close (void);
+#endif /* _RECORD_H_ */
--- 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
@@ -648,6 +649,78 @@ regcache_raw_write (struct regcache *reg
   if (gdbarch_cannot_store_register (get_regcache_arch (regcache), regnum))
     return;
 
+  /* Check for record */
+  if (gdb_is_recording && !record_not_record)
+    {
+      if (record_list && record_list->next)
+	{
+	  /* Not at the end of record list */
+	  /* Let user choice if he want to write memory or not. */
+	  if (regnum < 0)
+	    {
+	      if (!nquery (_
+			   ("Becuse GDB is not at the end of record list, it will destory the record in the next if set the values of all the registers. Do you want GDB do it?")))
+		{
+		  error (_("record: record pause the operation."));
+		}
+	    }
+	  else
+	    {
+	      if (!nquery (_
+			   ("Becuse GDB is not at the end of record list, it 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), regnum)))
+		{
+		  error (_("record: record pause the operation."));
+		}
+	    }
+
+	  /* Destory the record in the next */
+	  record_list_release_next (record_list);
+	}
+
+      /* Record to list as an instruction */
+      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."));
+	}
+      if (record_list)
+	{
+	  record_list->next = record_arch_list_head;
+	  record_arch_list_head->prev = record_list;
+	  record_list = record_arch_list_tail;
+	}
+      else
+	{
+	  record_list = record_arch_list_tail;
+	}
+    }
+
   /* If we have a valid copy of the register, and new value == old
      value, then don't bother doing the actual store. */
   if (regcache_valid_p (regcache, regnum)
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -39,6 +39,7 @@
 #include "gdbcore.h"
 #include "exceptions.h"
 #include "target-descriptions.h"
+#include "record.h"
 
 static void target_info (char *, int);
 
@@ -1190,8 +1191,52 @@ target_read_memory (CORE_ADDR memaddr, g
 }
 
 int
-target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
+target_write_memory (CORE_ADDR memaddr, const gdb_byte * myaddr, int len)
 {
+  /* Check for record */
+  if (gdb_is_recording && !record_not_record)
+    {
+      if (record_list && record_list->next)
+	{
+	  /* Not at the end of record list */
+	  /* Let user choice if he want to write memory or not. */
+	  if (!nquery (_
+		       ("Becuse GDB is not at the end of record list, it will destory the record in the next if write memory that addr is 0x%s and size is %d. Do you want GDB do it?"),
+		       paddr_nz (memaddr), len))
+	    {
+	      return EPERM;
+	    }
+
+	  /* Destory the record in the next */
+	  record_list_release_next (record_list);
+	}
+
+      /* Record 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 (memaddr, len))
+	{
+	  record_list_release (record_arch_list_tail);
+	  return EIO;
+	}
+      if (record_arch_list_add_end (0))
+	{
+	  record_list_release (record_arch_list_tail);
+	  return EIO;
+	}
+      if (record_list)
+	{
+	  record_list->next = record_arch_list_head;
+	  record_arch_list_head->prev = record_list;
+	  record_list = record_arch_list_tail;
+	}
+      else
+	{
+	  record_list = record_arch_list_tail;
+	}
+    }
+
   if (target_write (&current_target, TARGET_OBJECT_MEMORY, NULL,
 		    myaddr, memaddr, len) == len)
     return 0;
@@ -1702,6 +1747,16 @@ target_follow_fork (int follow_child)
 		  "could not find a target to follow fork");
 }
 
+void
+target_mourn_inferior (void)
+{
+  if (gdb_is_recording)
+    {
+      record_close ();
+    }
+  (*current_target.to_mourn_inferior) ();
+}
+
 /* Look for a target which can describe architectural features, starting
    from TARGET.  If we find one, return its description.  */
 
@@ -2065,6 +2120,10 @@ debug_to_close (int quitting)
 void
 target_close (struct target_ops *targ, int quitting)
 {
+  if (gdb_is_recording)
+    {
+      record_close ();
+    }
   if (targ->to_xclose != NULL)
     targ->to_xclose (targ, quitting);
   else if (targ->to_close != NULL)
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -861,8 +861,7 @@ int target_follow_fork (int follow_child
 
 /* The inferior process has died.  Do what is right.  */
 
-#define	target_mourn_inferior()	\
-     (*current_target.to_mourn_inferior) ()
+extern void target_mourn_inferior (void);
 
 /* Does target have enough data to do a run or attach command? */
 

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