]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
2008-12-26 Michael Snyder <msnyder@vmware.com>
authorMichael Snyder <msnyder@vmware.com>
Fri, 26 Dec 2008 21:09:13 +0000 (21:09 +0000)
committerMichael Snyder <msnyder@vmware.com>
Fri, 26 Dec 2008 21:09:13 +0000 (21:09 +0000)
* Marker: adding teawater patches to branch.

20 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/configure.tgt
gdb/doc/gdb.texinfo
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/i386-linux-tdep.c
gdb/i386-tdep.c
gdb/i386-tdep.h
gdb/infrun.c
gdb/linux-record.c [new file with mode: 0644]
gdb/linux-record.h [new file with mode: 0644]
gdb/record.c [new file with mode: 0644]
gdb/record.h [new file with mode: 0644]
gdb/target.c
gdb/target.h
gdb/testsuite/configure
gdb/testsuite/configure.ac
gdb/testsuite/gdb.twreverse/machinestate.exp

index c78678b7bcf61973d7905cb805e30bab6d7e8671..39ecb43eb4d3e5fa19d939ab37f5e83050d9f003 100644 (file)
@@ -1,3 +1,7 @@
+2008-12-26  Michael Snyder  <msnyder@vmware.com>
+
+       * Marker: adding teawater patches to branch.
+
 2008-12-26  Sandra Loosemore  <sandra@codesourcery.com>
 
        * breakpoint.c (update_watchpoint): Refactor to avoid compiler
index 47b3be08538a0a06c64d3a2129ae34832b9fcc32..0935ffe1ddbcbfd52b091a33f88ca8faed64d0b9 100644 (file)
@@ -515,7 +515,7 @@ ALL_TARGET_OBS = \
        xcoffread.o \
        prologue-value.o \
        symfile-mem.o \
-       corelow.o
+       corelow.o linux-record.o
 
 # Host-dependent makefile fragment comes in here.
 @host_makefile_frag@
@@ -657,7 +657,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
        valarith.c valops.c valprint.c value.c varobj.c vec.c \
        wrapper.c \
        xml-tdesc.c xml-support.c \
-       inferior.c
+       inferior.c record.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -808,7 +808,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
        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 \
-       inferior.o osdata.o
+       inferior.o osdata.o record.o
 
 TSOBS = inflow.o
 
@@ -1297,7 +1297,7 @@ ALLDEPFILES = \
        inf-ptrace.c inf-ttrace.c \
        irix5-nat.c \
        libunwind-frame.c \
-       linux-fork.c \
+       linux-fork.c linux-record.c \
        m68hc11-tdep.c \
        m32r-tdep.c \
        m32r-linux-nat.c m32r-linux-tdep.c \
index b9cd21bdc05387378d80fcebaa4c26a6dac99ad5..d81cdedf6027339a1a285c9b0483335b4de84234 100644 (file)
@@ -190,7 +190,8 @@ i[34567]86-*-solaris*)
 i[34567]86-*-linux*)
        # Target: Intel 386 running GNU/Linux
        gdb_target_obs="i386-tdep.o i386-linux-tdep.o glibc-tdep.o i387-tdep.o \
-                       solib.o solib-svr4.o symfile-mem.o corelow.o"
+                       solib.o solib-svr4.o symfile-mem.o corelow.o \
+                       linux-record.o"
        build_gdbserver=yes
        ;;
 i[34567]86-*-gnu*)
@@ -513,7 +514,8 @@ x86_64-*-linux*)
        # Target: GNU/Linux x86-64
        gdb_target_obs="amd64-tdep.o amd64-linux-tdep.o i386-tdep.o \
                        i387-tdep.o i386-linux-tdep.o glibc-tdep.o \
-                       solib.o solib-svr4.o corelow.o symfile-mem.o"
+                       solib.o solib-svr4.o corelow.o symfile-mem.o \
+                       linux-record.o"
        build_gdbserver=yes
        ;;
 x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu)
index 6ef124c24e7f236a094708e7fcbba79175a55e8e..c7589528c718faae8e24ebfae1c6dbaf4f60d3cc 100644 (file)
@@ -144,6 +144,7 @@ software in general.  We will miss him.
 * Running::                     Running programs under @value{GDBN}
 * Stopping::                    Stopping and continuing
 * Reverse Execution::           Running programs backward
+* Process record and replay::   Recording inferior's execution and replaying it
 * Stack::                       Examining the stack
 * Source::                      Examining source files
 * Data::                        Examining data
@@ -4964,6 +4965,112 @@ This is the default.
 @end table
 
 
+@node Process record and replay
+@chapter Recording inferior's execution and replaying it
+@cindex process record and replay
+@cindex recording inferior's execution and replaying it
+
+In a architecture environment that supports process record and replay,
+process record and replay target can record a log of the process execution,
+and replay it with both forward and reverse execute commands.
+
+When this target is in use, if the execution log includes the record for
+the next instruction, @value{GDBN} will debug in replay mode.  So inferior
+will not really execute and all the execution events are taken from the
+execution log.  Just the values of registers (include pc register) and
+memory of the inferior will be changed.
+
+Otherwise, @value{GDBN} will debug in record mode.  So inferior will
+execute normally and @value{GDBN} will record the execution log.
+
+If you are debugging in a architecture environment that supports
+process record and replay, @value{GDBN} provides the following commands.
+
+@table @code
+@kindex target record
+@kindex record
+@kindex rec
+@item target record
+This a standard command to start process record and replay target.
+Process record and replay target can only debug a process that already
+running.  Therefore you need to first start the process @code{run},
+and then start the recording @code{target record}.
+
+Both @code{record} and @code{rec} are the aliases of @code{target record}.
+
+Displaced stepping function will disable when process record and replay
+target is opened.  Because process record and replay target doesn't
+support displaced stepping function.
+
+If inferior in non-stop mode (non-stop) or in asynchronous mode
+(target-async), process record and replay target can't be open because
+it doesn't support these two modes.
+
+@kindex stoprecord
+@kindex sr
+@item stoprecord
+Stop process record and replay target at once.  When Process record and
+replay target stops, all the execution log will be deleted and the inferior
+will either be terminated, or remain in its final state.
+
+When you stop the process record and replay target in record mode (at the
+end of the execution log), the inferior will be stopped at the next
+instruction that would have been recorded.  In other words, if you record
+for a while and then stop recording, the inferior process will be left in
+the same state as if recording never happened.
+
+On the other hand, if the process record and replay target is stopped while
+in replay mode (that is, not at the end of the execution log but at some
+earlier point), the inferior process will become ``live'' at that earlier state,
+and it will then be possible to continue debugging the process ``live'' from
+that state.
+
+When the inferior process exits, or @value{GDBN} detaches from it, process
+record and replay target will automatically stop itself.
+
+@kindex set record-insn-number-max
+@item set record-insn-number-max @var{limit}
+Set the limit of instructions to be recorded.  Default value is 200000.
+
+In this case, if record instructions number is bigger than @var{limit},
+@value{GDBN} will auto delete the earliest recorded instruction execute
+log.
+
+If set to 0, @value{GDBN} will not delete the earliest recorded instruction
+execute log.  Record instructions number limit function will disable.
+
+@kindex show record-insn-number-max
+@item show record-insn-number-max
+Show the value of recorded instructions limit.
+
+@kindex set record-stop-at-limit
+@item set record-stop-at-limit on
+Set the behavior when record instructions limit is reached.
+This is the default mode.  Meaning that @value{GDBN} will stop ask user
+want close @code{record-stop-at-limit} or stop inferior.
+
+@item set record-stop-at-limit off
+This mean that @value{GDBN} will auto delete the oldest record to make
+room for each new one.
+
+@kindex show record-stop-at-limit
+@item show record-stop-at-limit
+Show the value of record-stop-at-limit.
+
+@kindex info record-insn-number
+@item info record-insn-number
+Show the current number of recorded instructions.
+
+@kindex delrecord
+@kindex dr
+@item delrecord
+When record target running in replay mode (``in the past''), delete the
+subsequent execution log and begin to record a new execution log starting
+from the current address.  It means you will abandon the previously
+recorded ``future'' and begin recording a new ``future''.
+@end table
+
+
 @node Stack
 @chapter Examining the Stack
 
index dd6ad7f480bacd3fa6a90acb1570f29e2d6018e4..de07768efacd0779d0536e9bd3642ce15acbb9b3 100644 (file)
@@ -237,6 +237,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_process_record_ftype *process_record;
+  gdbarch_process_record_dasm_ftype *process_record_dasm;
   gdbarch_target_signal_from_host_ftype *target_signal_from_host;
   gdbarch_target_signal_to_host_ftype *target_signal_to_host;
   gdbarch_record_special_symbol_ftype *record_special_symbol;
@@ -369,6 +371,8 @@ struct gdbarch startup_gdbarch =
   0,  /* core_read_description */
   0,  /* static_transform_name */
   0,  /* sofun_address_maybe_missing */
+  0,  /* process_record */
+  0,  /* process_record_dasm */
   default_target_signal_from_host,  /* target_signal_from_host */
   default_target_signal_to_host,  /* target_signal_to_host */
   0,  /* record_special_symbol */
@@ -622,6 +626,8 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of core_read_description, has predicate */
   /* Skip verify of static_transform_name, has predicate */
   /* Skip verify of sofun_address_maybe_missing, invalid_p == 0 */
+  /* Skip verify of process_record, has predicate */
+  /* Skip verify of process_record_dasm, has predicate */
   /* Skip verify of target_signal_from_host, invalid_p == 0 */
   /* Skip verify of target_signal_to_host, invalid_p == 0 */
   /* Skip verify of record_special_symbol, has predicate */
@@ -921,6 +927,18 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "gdbarch_dump: print_vector_info = <0x%lx>\n",
                       (long) gdbarch->print_vector_info);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_process_record_p() = %d\n",
+                      gdbarch_process_record_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: process_record = <0x%lx>\n",
+                      (long) gdbarch->process_record);
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_process_record_dasm_p() = %d\n",
+                      gdbarch_process_record_dasm_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: process_record_dasm = <0x%lx>\n",
+                      (long) gdbarch->process_record_dasm);
   fprintf_unfiltered (file,
                       "gdbarch_dump: ps_regnum = %s\n",
                       plongest (gdbarch->ps_regnum));
@@ -3185,6 +3203,54 @@ set_gdbarch_sofun_address_maybe_missing (struct gdbarch *gdbarch,
   gdbarch->sofun_address_maybe_missing = sofun_address_maybe_missing;
 }
 
+int
+gdbarch_process_record_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->process_record != NULL;
+}
+
+int
+gdbarch_process_record (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->process_record != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_process_record called\n");
+  return gdbarch->process_record (gdbarch, addr);
+}
+
+void
+set_gdbarch_process_record (struct gdbarch *gdbarch,
+                            gdbarch_process_record_ftype process_record)
+{
+  gdbarch->process_record = process_record;
+}
+
+int
+gdbarch_process_record_dasm_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->process_record_dasm != NULL;
+}
+
+void
+gdbarch_process_record_dasm (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->process_record_dasm != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_process_record_dasm called\n");
+  gdbarch->process_record_dasm (gdbarch);
+}
+
+void
+set_gdbarch_process_record_dasm (struct gdbarch *gdbarch,
+                                 gdbarch_process_record_dasm_ftype process_record_dasm)
+{
+  gdbarch->process_record_dasm = process_record_dasm;
+}
+
 enum target_signal
 gdbarch_target_signal_from_host (struct gdbarch *gdbarch, int signo)
 {
index 35f8a36f4cd9a77a898cad5515e719a4b645aa27..19b1b1f4565424ef8bfe94365745cf54879250f4 100644 (file)
@@ -789,6 +789,20 @@ extern void set_gdbarch_static_transform_name (struct gdbarch *gdbarch, gdbarch_
 extern int gdbarch_sofun_address_maybe_missing (struct gdbarch *gdbarch);
 extern void set_gdbarch_sofun_address_maybe_missing (struct gdbarch *gdbarch, int sofun_address_maybe_missing);
 
+/* For the process record and replay target */
+
+extern int gdbarch_process_record_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_process_record_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern int gdbarch_process_record (struct gdbarch *gdbarch, CORE_ADDR addr);
+extern void set_gdbarch_process_record (struct gdbarch *gdbarch, gdbarch_process_record_ftype *process_record);
+
+extern int gdbarch_process_record_dasm_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_process_record_dasm_ftype) (struct gdbarch *gdbarch);
+extern void gdbarch_process_record_dasm (struct gdbarch *gdbarch);
+extern void set_gdbarch_process_record_dasm (struct gdbarch *gdbarch, gdbarch_process_record_dasm_ftype *process_record_dasm);
+
 /* Signal translation: translate inferior's signal (host's) number into
    GDB's representation. */
 
index 79ca862a2aac979630686d1ec74c51429338e714..8a827f467e29d47ac512f0b8425310d4989a377b 100755 (executable)
@@ -698,6 +698,10 @@ F:char *:static_transform_name:char *name:name
 # Set if the address in N_SO or N_FUN stabs may be zero.
 v:int:sofun_address_maybe_missing:::0:0::0
 
+# For the process record and replay target
+M:int:process_record:CORE_ADDR addr:addr
+M:void:process_record_dasm:void
+
 # Signal translation: translate inferior's signal (host's) number into
 # GDB's representation.
 m:enum target_signal:target_signal_from_host:int signo:signo::default_target_signal_from_host::0
index 5284f4a6ead34134c7e822565f56cb5682eefd01..6b8bf9b62678a62099b2db3cf2429a6e10fa5947 100644 (file)
 #include "arch-utils.h"
 #include "regset.h"
 
+#include "record.h"
+#include "linux-record.h"
+#include <stdint.h>
+
 /* Supported register note sections.  */
 static struct core_regset_section i386_linux_regset_sections[] =
 {
@@ -346,6 +350,37 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
      restarted.  */
   regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1);
 }
+
+/* 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 linux_record_tdep_t linux_record_tdep;
+
+static int
+i386_linux_intx80_sysenter_record (void)
+{
+  int ret;
+  uint32_t tmpu32;
+
+  regcache_raw_read (record_regcache, I386_EAX_REGNUM, (gdb_byte *) & tmpu32);
+
+  ret = record_linux_system_call (tmpu32, &linux_record_tdep);
+  if (ret)
+    {
+      return ret;
+    }
+
+  /* Record the return of system call.  */
+  if (record_arch_list_add_reg (I386_EAX_REGNUM))
+    {
+      return -1;
+    }
+
+  return 0;
+}
 \f
 
 /* The register sets used in GNU/Linux ELF core-dumps are identical to
@@ -413,6 +448,145 @@ static int i386_linux_sc_reg_offset[] =
   0 * 4                                /* %gs */
 };
 
+/* These macros are the size of the type that will be used 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_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_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_termios               36
+#define I386_RECORD_SIZE_termios2              44
+#define I386_RECORD_SIZE_pid_t                 4
+#define I386_RECORD_SIZE_winsize               8
+#define I386_RECORD_SIZE_char                  8
+#define I386_RECORD_SIZE_serial_struct         60
+#define I386_RECORD_SIZE_serial_icounter_struct        80
+#define I386_RECORD_SIZE_hayes_esp_config      12
+
+/* 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_IOCTL_TCGETS               0x5401
+#define I386_RECORD_IOCTL_TCSETS               0x5402
+#define I386_RECORD_IOCTL_TCSETSW              0x5403
+#define I386_RECORD_IOCTL_TCSETSF              0x5404
+#define I386_RECORD_IOCTL_TCGETA               0x5405
+#define I386_RECORD_IOCTL_TCSETA               0x5406
+#define I386_RECORD_IOCTL_TCSETAW              0x5407
+#define I386_RECORD_IOCTL_TCSETAF              0x5408
+#define I386_RECORD_IOCTL_TCSBRK               0x5409
+#define I386_RECORD_IOCTL_TCXONC               0x540A
+#define I386_RECORD_IOCTL_TCFLSH               0x540B
+#define I386_RECORD_IOCTL_TIOCEXCL             0x540C
+#define I386_RECORD_IOCTL_TIOCNXCL             0x540D
+#define I386_RECORD_IOCTL_TIOCSCTTY            0x540E
+#define I386_RECORD_IOCTL_TIOCGPGRP            0x540F
+#define I386_RECORD_IOCTL_TIOCSPGRP            0x5410
+#define I386_RECORD_IOCTL_TIOCOUTQ             0x5411
+#define I386_RECORD_IOCTL_TIOCSTI              0x5412
+#define I386_RECORD_IOCTL_TIOCGWINSZ           0x5413
+#define I386_RECORD_IOCTL_TIOCSWINSZ           0x5414
+#define I386_RECORD_IOCTL_TIOCMGET             0x5415
+#define I386_RECORD_IOCTL_TIOCMBIS             0x5416
+#define I386_RECORD_IOCTL_TIOCMBIC             0x5417
+#define I386_RECORD_IOCTL_TIOCMSET             0x5418
+#define I386_RECORD_IOCTL_TIOCGSOFTCAR         0x5419
+#define I386_RECORD_IOCTL_TIOCSSOFTCAR         0x541A
+#define I386_RECORD_IOCTL_FIONREAD             0x541B
+#define I386_RECORD_IOCTL_TIOCINQ              I386_RECORD_IOCTL_FIONREAD
+#define I386_RECORD_IOCTL_TIOCLINUX            0x541C
+#define I386_RECORD_IOCTL_TIOCCONS             0x541D
+#define I386_RECORD_IOCTL_TIOCGSERIAL          0x541E
+#define I386_RECORD_IOCTL_TIOCSSERIAL          0x541F
+#define I386_RECORD_IOCTL_TIOCPKT              0x5420
+#define I386_RECORD_IOCTL_FIONBIO              0x5421
+#define I386_RECORD_IOCTL_TIOCNOTTY            0x5422
+#define I386_RECORD_IOCTL_TIOCSETD             0x5423
+#define I386_RECORD_IOCTL_TIOCGETD             0x5424
+#define I386_RECORD_IOCTL_TCSBRKP              0x5425
+#define I386_RECORD_IOCTL_TIOCTTYGSTRUCT       0x5426
+#define I386_RECORD_IOCTL_TIOCSBRK             0x5427
+#define I386_RECORD_IOCTL_TIOCCBRK             0x5428
+#define I386_RECORD_IOCTL_TIOCGSID             0x5429
+#define I386_RECORD_IOCTL_TCGETS2              0x802c542a
+#define I386_RECORD_IOCTL_TCSETS2              0x402c542b
+#define I386_RECORD_IOCTL_TCSETSW2             0x402c542c
+#define I386_RECORD_IOCTL_TCSETSF2             0x402c542d
+#define I386_RECORD_IOCTL_TIOCGPTN             0x80045430
+#define I386_RECORD_IOCTL_TIOCSPTLCK           0x40045431
+#define I386_RECORD_IOCTL_FIONCLEX             0x5450
+#define I386_RECORD_IOCTL_FIOCLEX              0x5451
+#define I386_RECORD_IOCTL_FIOASYNC             0x5452
+#define I386_RECORD_IOCTL_TIOCSERCONFIG                0x5453
+#define I386_RECORD_IOCTL_TIOCSERGWILD         0x5454
+#define I386_RECORD_IOCTL_TIOCSERSWILD         0x5455
+#define I386_RECORD_IOCTL_TIOCGLCKTRMIOS       0x5456
+#define I386_RECORD_IOCTL_TIOCSLCKTRMIOS       0x5457
+#define I386_RECORD_IOCTL_TIOCSERGSTRUCT       0x5458
+#define I386_RECORD_IOCTL_TIOCSERGETLSR        0x5459
+#define I386_RECORD_IOCTL_TIOCSERGETMULTI      0x545A
+#define I386_RECORD_IOCTL_TIOCSERSETMULTI      0x545B
+#define I386_RECORD_IOCTL_TIOCMIWAIT           0x545C
+#define I386_RECORD_IOCTL_TIOCGICOUNT          0x545D
+#define I386_RECORD_IOCTL_TIOCGHAYESESP                0x545E
+#define I386_RECORD_IOCTL_TIOCSHAYESESP                0x545F
+#define I386_RECORD_IOCTL_FIOQSIZE             0x5460
+
 static void
 i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
@@ -440,6 +614,150 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   tdep->sc_reg_offset = i386_linux_sc_reg_offset;
   tdep->sc_num_regs = ARRAY_SIZE (i386_linux_sc_reg_offset);
 
+  /* Initial the linux_record_tdep */
+  linux_record_tdep.size__old_kernel_stat = I386_RECORD_SIZE__old_kernel_stat;
+  linux_record_tdep.size_tms = I386_RECORD_SIZE_tms;
+  linux_record_tdep.size_loff_t = I386_RECORD_SIZE_loff_t;
+  linux_record_tdep.size_flock = I386_RECORD_SIZE_flock;
+  linux_record_tdep.size_oldold_utsname = I386_RECORD_SIZE_oldold_utsname;
+  linux_record_tdep.size_ustat = I386_RECORD_SIZE_ustat;
+  linux_record_tdep.size_old_sigaction = I386_RECORD_SIZE_old_sigaction;
+  linux_record_tdep.size_old_sigset_t = I386_RECORD_SIZE_old_sigset_t;
+  linux_record_tdep.size_rlimit = I386_RECORD_SIZE_rlimit;
+  linux_record_tdep.size_rusage = I386_RECORD_SIZE_rusage;
+  linux_record_tdep.size_timeval = I386_RECORD_SIZE_timeval;
+  linux_record_tdep.size_timezone = I386_RECORD_SIZE_timezone;
+  linux_record_tdep.size_old_gid_t = I386_RECORD_SIZE_old_gid_t;
+  linux_record_tdep.size_old_uid_t = I386_RECORD_SIZE_old_uid_t;
+  linux_record_tdep.size_fd_set = I386_RECORD_SIZE_fd_set;
+  linux_record_tdep.size_dirent = I386_RECORD_SIZE_dirent;
+  linux_record_tdep.size_dirent64 = I386_RECORD_SIZE_dirent64;
+  linux_record_tdep.size_statfs = I386_RECORD_SIZE_statfs;
+  linux_record_tdep.size_statfs64 = I386_RECORD_SIZE_statfs64;
+  linux_record_tdep.size_sockaddr = I386_RECORD_SIZE_sockaddr;
+  linux_record_tdep.size_int = I386_RECORD_SIZE_int;
+  linux_record_tdep.size_long = I386_RECORD_SIZE_long;
+  linux_record_tdep.size_ulong = I386_RECORD_SIZE_ulong;
+  linux_record_tdep.size_msghdr = I386_RECORD_SIZE_msghdr;
+  linux_record_tdep.size_itimerval = I386_RECORD_SIZE_itimerval;
+  linux_record_tdep.size_stat = I386_RECORD_SIZE_stat;
+  linux_record_tdep.size_old_utsname = I386_RECORD_SIZE_old_utsname;
+  linux_record_tdep.size_sysinfo = I386_RECORD_SIZE_sysinfo;
+  linux_record_tdep.size_msqid_ds = I386_RECORD_SIZE_msqid_ds;
+  linux_record_tdep.size_shmid_ds = I386_RECORD_SIZE_shmid_ds;
+  linux_record_tdep.size_new_utsname = I386_RECORD_SIZE_new_utsname;
+  linux_record_tdep.size_timex = I386_RECORD_SIZE_timex;
+  linux_record_tdep.size_mem_dqinfo = I386_RECORD_SIZE_mem_dqinfo;
+  linux_record_tdep.size_if_dqblk = I386_RECORD_SIZE_if_dqblk;
+  linux_record_tdep.size_fs_quota_stat = I386_RECORD_SIZE_fs_quota_stat;
+  linux_record_tdep.size_timespec = I386_RECORD_SIZE_timespec;
+  linux_record_tdep.size_pollfd = I386_RECORD_SIZE_pollfd;
+  linux_record_tdep.size_NFS_FHSIZE = I386_RECORD_SIZE_NFS_FHSIZE;
+  linux_record_tdep.size_knfsd_fh = I386_RECORD_SIZE_knfsd_fh;
+  linux_record_tdep.size_TASK_COMM_LEN = I386_RECORD_SIZE_TASK_COMM_LEN;
+  linux_record_tdep.size_sigaction = I386_RECORD_SIZE_sigaction;
+  linux_record_tdep.size_sigset_t = I386_RECORD_SIZE_sigset_t;
+  linux_record_tdep.size_siginfo_t = I386_RECORD_SIZE_siginfo_t;
+  linux_record_tdep.size_cap_user_data_t = I386_RECORD_SIZE_cap_user_data_t;
+  linux_record_tdep.size_stack_t = I386_RECORD_SIZE_stack_t;
+  linux_record_tdep.size_off_t = I386_RECORD_SIZE_off_t;
+  linux_record_tdep.size_stat64 = I386_RECORD_SIZE_stat64;
+  linux_record_tdep.size_gid_t = I386_RECORD_SIZE_gid_t;
+  linux_record_tdep.size_uid_t = I386_RECORD_SIZE_uid_t;
+  linux_record_tdep.size_PAGE_SIZE = I386_RECORD_SIZE_PAGE_SIZE;
+  linux_record_tdep.size_flock64 = I386_RECORD_SIZE_flock64;
+  linux_record_tdep.size_user_desc = I386_RECORD_SIZE_user_desc;
+  linux_record_tdep.size_io_event = I386_RECORD_SIZE_io_event;
+  linux_record_tdep.size_iocb = I386_RECORD_SIZE_iocb;
+  linux_record_tdep.size_epoll_event = I386_RECORD_SIZE_epoll_event;
+  linux_record_tdep.size_itimerspec = I386_RECORD_SIZE_itimerspec;
+  linux_record_tdep.size_mq_attr = I386_RECORD_SIZE_mq_attr;
+  linux_record_tdep.size_siginfo = I386_RECORD_SIZE_siginfo;
+  linux_record_tdep.size_termios = I386_RECORD_SIZE_termios;
+  linux_record_tdep.size_termios2 = I386_RECORD_SIZE_termios2;
+  linux_record_tdep.size_pid_t = I386_RECORD_SIZE_pid_t;
+  linux_record_tdep.size_winsize = I386_RECORD_SIZE_winsize;
+  linux_record_tdep.size_char = I386_RECORD_SIZE_char;
+  linux_record_tdep.size_serial_struct = I386_RECORD_SIZE_serial_struct;
+  linux_record_tdep.size_serial_icounter_struct =
+    I386_RECORD_SIZE_serial_icounter_struct;
+  linux_record_tdep.size_hayes_esp_config = I386_RECORD_SIZE_hayes_esp_config;
+
+  linux_record_tdep.ioctl_TCGETS = I386_RECORD_IOCTL_TCGETS;
+  linux_record_tdep.ioctl_TCSETS = I386_RECORD_IOCTL_TCSETS;
+  linux_record_tdep.ioctl_TCSETSW = I386_RECORD_IOCTL_TCSETSW;
+  linux_record_tdep.ioctl_TCSETSF = I386_RECORD_IOCTL_TCSETSF;
+  linux_record_tdep.ioctl_TCGETA = I386_RECORD_IOCTL_TCGETA;
+  linux_record_tdep.ioctl_TCSETA = I386_RECORD_IOCTL_TCSETA;
+  linux_record_tdep.ioctl_TCSETAW = I386_RECORD_IOCTL_TCSETAW;
+  linux_record_tdep.ioctl_TCSETAF = I386_RECORD_IOCTL_TCSETAF;
+  linux_record_tdep.ioctl_TCSBRK = I386_RECORD_IOCTL_TCSBRK;
+  linux_record_tdep.ioctl_TCXONC = I386_RECORD_IOCTL_TCXONC;
+  linux_record_tdep.ioctl_TCFLSH = I386_RECORD_IOCTL_TCFLSH;
+  linux_record_tdep.ioctl_TIOCEXCL = I386_RECORD_IOCTL_TIOCEXCL;
+  linux_record_tdep.ioctl_TIOCNXCL = I386_RECORD_IOCTL_TIOCNXCL;
+  linux_record_tdep.ioctl_TIOCSCTTY = I386_RECORD_IOCTL_TIOCSCTTY;
+  linux_record_tdep.ioctl_TIOCGPGRP = I386_RECORD_IOCTL_TIOCGPGRP;
+  linux_record_tdep.ioctl_TIOCSPGRP = I386_RECORD_IOCTL_TIOCSPGRP;
+  linux_record_tdep.ioctl_TIOCOUTQ = I386_RECORD_IOCTL_TIOCOUTQ;
+  linux_record_tdep.ioctl_TIOCSTI = I386_RECORD_IOCTL_TIOCSTI;
+  linux_record_tdep.ioctl_TIOCGWINSZ = I386_RECORD_IOCTL_TIOCGWINSZ;
+  linux_record_tdep.ioctl_TIOCSWINSZ = I386_RECORD_IOCTL_TIOCSWINSZ;
+  linux_record_tdep.ioctl_TIOCMGET = I386_RECORD_IOCTL_TIOCMGET;
+  linux_record_tdep.ioctl_TIOCMBIS = I386_RECORD_IOCTL_TIOCMBIS;
+  linux_record_tdep.ioctl_TIOCMBIC = I386_RECORD_IOCTL_TIOCMBIC;
+  linux_record_tdep.ioctl_TIOCMSET = I386_RECORD_IOCTL_TIOCMSET;
+  linux_record_tdep.ioctl_TIOCGSOFTCAR = I386_RECORD_IOCTL_TIOCGSOFTCAR;
+  linux_record_tdep.ioctl_TIOCSSOFTCAR = I386_RECORD_IOCTL_TIOCSSOFTCAR;
+  linux_record_tdep.ioctl_FIONREAD = I386_RECORD_IOCTL_FIONREAD;
+  linux_record_tdep.ioctl_TIOCINQ = I386_RECORD_IOCTL_TIOCINQ;
+  linux_record_tdep.ioctl_TIOCLINUX = I386_RECORD_IOCTL_TIOCLINUX;
+  linux_record_tdep.ioctl_TIOCCONS = I386_RECORD_IOCTL_TIOCCONS;
+  linux_record_tdep.ioctl_TIOCGSERIAL = I386_RECORD_IOCTL_TIOCGSERIAL;
+  linux_record_tdep.ioctl_TIOCSSERIAL = I386_RECORD_IOCTL_TIOCSSERIAL;
+  linux_record_tdep.ioctl_TIOCPKT = I386_RECORD_IOCTL_TIOCPKT;
+  linux_record_tdep.ioctl_FIONBIO = I386_RECORD_IOCTL_FIONBIO;
+  linux_record_tdep.ioctl_TIOCNOTTY = I386_RECORD_IOCTL_TIOCNOTTY;
+  linux_record_tdep.ioctl_TIOCSETD = I386_RECORD_IOCTL_TIOCSETD;
+  linux_record_tdep.ioctl_TIOCGETD = I386_RECORD_IOCTL_TIOCGETD;
+  linux_record_tdep.ioctl_TCSBRKP = I386_RECORD_IOCTL_TCSBRKP;
+  linux_record_tdep.ioctl_TIOCTTYGSTRUCT = I386_RECORD_IOCTL_TIOCTTYGSTRUCT;
+  linux_record_tdep.ioctl_TIOCSBRK = I386_RECORD_IOCTL_TIOCSBRK;
+  linux_record_tdep.ioctl_TIOCCBRK = I386_RECORD_IOCTL_TIOCCBRK;
+  linux_record_tdep.ioctl_TIOCGSID = I386_RECORD_IOCTL_TIOCGSID;
+  linux_record_tdep.ioctl_TCGETS2 = I386_RECORD_IOCTL_TCGETS2;
+  linux_record_tdep.ioctl_TCSETS2 = I386_RECORD_IOCTL_TCSETS2;
+  linux_record_tdep.ioctl_TCSETSW2 = I386_RECORD_IOCTL_TCSETSW2;
+  linux_record_tdep.ioctl_TCSETSF2 = I386_RECORD_IOCTL_TCSETSF2;
+  linux_record_tdep.ioctl_TIOCGPTN = I386_RECORD_IOCTL_TIOCGPTN;
+  linux_record_tdep.ioctl_TIOCSPTLCK = I386_RECORD_IOCTL_TIOCSPTLCK;
+  linux_record_tdep.ioctl_FIONCLEX = I386_RECORD_IOCTL_FIONCLEX;
+  linux_record_tdep.ioctl_FIOCLEX = I386_RECORD_IOCTL_FIOCLEX;
+  linux_record_tdep.ioctl_FIOASYNC = I386_RECORD_IOCTL_FIOASYNC;
+  linux_record_tdep.ioctl_TIOCSERCONFIG = I386_RECORD_IOCTL_TIOCSERCONFIG;
+  linux_record_tdep.ioctl_TIOCSERGWILD = I386_RECORD_IOCTL_TIOCSERGWILD;
+  linux_record_tdep.ioctl_TIOCSERSWILD = I386_RECORD_IOCTL_TIOCSERSWILD;
+  linux_record_tdep.ioctl_TIOCGLCKTRMIOS = I386_RECORD_IOCTL_TIOCGLCKTRMIOS;
+  linux_record_tdep.ioctl_TIOCSLCKTRMIOS = I386_RECORD_IOCTL_TIOCSLCKTRMIOS;
+  linux_record_tdep.ioctl_TIOCSERGSTRUCT = I386_RECORD_IOCTL_TIOCSERGSTRUCT;
+  linux_record_tdep.ioctl_TIOCSERGETLSR = I386_RECORD_IOCTL_TIOCSERGETLSR;
+  linux_record_tdep.ioctl_TIOCSERGETMULTI = I386_RECORD_IOCTL_TIOCSERGETMULTI;
+  linux_record_tdep.ioctl_TIOCSERSETMULTI = I386_RECORD_IOCTL_TIOCSERSETMULTI;
+  linux_record_tdep.ioctl_TIOCMIWAIT = I386_RECORD_IOCTL_TIOCMIWAIT;
+  linux_record_tdep.ioctl_TIOCGICOUNT = I386_RECORD_IOCTL_TIOCGICOUNT;
+  linux_record_tdep.ioctl_TIOCGHAYESESP = I386_RECORD_IOCTL_TIOCGHAYESESP;
+  linux_record_tdep.ioctl_TIOCSHAYESESP = I386_RECORD_IOCTL_TIOCSHAYESESP;
+  linux_record_tdep.ioctl_FIOQSIZE = I386_RECORD_IOCTL_FIOQSIZE;
+
+  linux_record_tdep.arg1 = I386_EBX_REGNUM;
+  linux_record_tdep.arg2 = I386_ECX_REGNUM;
+  linux_record_tdep.arg3 = I386_EDX_REGNUM;
+  linux_record_tdep.arg4 = I386_ESI_REGNUM;
+  linux_record_tdep.arg5 = I386_EDI_REGNUM;
+
+  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);
index edaac21b186216c855db8a0cd0ae63be08c59179..fba6ceedad26b9fc3831dfccef3ba1ebf9f8dc0d 100644 (file)
@@ -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[] =
@@ -2638,135 +2641,3094 @@ i386_skip_permanent_breakpoint (struct regcache *regcache)
 }
 
 
-\f
-static struct gdbarch *
-i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
-{
-  struct gdbarch_tdep *tdep;
-  struct gdbarch *gdbarch;
+#define PREFIX_REPZ    0x01
+#define PREFIX_REPNZ   0x02
+#define PREFIX_LOCK    0x04
+#define PREFIX_DATA    0x08
+#define PREFIX_ADDR    0x10
 
-  /* If there is already a candidate, use it.  */
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return arches->gdbarch;
+/* 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))
+    {
+      if (record_debug)
+       {
+         printf_unfiltered (_
+                            ("Process record: error reading memory at addr 0x%s len = 1.\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;
 
-  tdep->st0_regnum = I386_ST0_REGNUM;
+  *addr = 0;
+  if (aflag)
+    {
+      /* 32 bits */
+      int havesib = 0;
+      uint8_t scale = 0;
+      uint8_t index = 0;
+      uint8_t base = rm;
 
-  /* 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;
+      if (base == 4)
+       {
+         havesib = 1;
+         if (target_read_memory (i386_record_pc, &tmpu8, 1))
+           {
+             if (record_debug)
+               {
+                 printf_unfiltered (_
+                                    ("Process record: error reading memory at addr 0x%s len = 1.\n"),
+                                    paddr_nz (i386_record_pc));
+               }
+             return (-1);
+           }
+         i386_record_pc++;
+         scale = (tmpu8 >> 6) & 3;
+         index = ((tmpu8 >> 3) & 7);
+         base = (tmpu8 & 7);
+       }
 
-  /* I386_NUM_XREGS includes %mxcsr, so substract one.  */
-  tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+      switch (mod)
+       {
+       case 0:
+         if ((base & 7) == 5)
+           {
+             base = 0xff;
+             if (target_read_memory (i386_record_pc, (gdb_byte *) addr, 4))
+               {
+                 if (record_debug)
+                   {
+                     printf_unfiltered (_
+                                        ("Process record: error reading memory at addr 0x%s len = 4.\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))
+           {
+             if (record_debug)
+               {
+                 printf_unfiltered (_
+                                    ("Process record: error reading memory at addr 0x%s len = 1.\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))
+           {
+             if (record_debug)
+               {
+                 printf_unfiltered (_
+                                    ("Process record: error reading memory at addr 0x%s len = 4.\n"),
+                                    paddr_nz (i386_record_pc));
+               }
+             return (-1);
+           }
+         i386_record_pc += 4;
+         break;
+       }
 
-  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;
+      if (base != 0xff)
+       {
+         regcache_raw_read (record_regcache, base, (gdb_byte *) & tmpu32);
+         *addr += tmpu32;
+       }
 
-  /* 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);
+      /* 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))
+               {
+                 if (record_debug)
+                   {
+                     printf_unfiltered (_
+                                        ("Process record: error reading memory at addr 0x%s len = 2.\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))
+           {
+             if (record_debug)
+               {
+                 printf_unfiltered (_
+                                    ("Process record: error reading memory at addr 0x%s len = 1.\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))
+           {
+             if (record_debug)
+               {
+                 printf_unfiltered (_
+                                    ("Process record: error reading memory at addr 0x%s len = 2.\n"),
+                                    paddr_nz (i386_record_pc));
+               }
+             return (-1);
+           }
+         i386_record_pc += 2;
+         *addr = (int16_t) tmpu16;
+         break;
+       }
 
-  /* 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);
+      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;
+    }
 
-  /* 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);
+no_rm:
+  return (0);
+}
 
-  /* 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) */
+/* 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;
 
-  /* 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 (override)
+    {
+      if (record_debug)
+       printf_unfiltered (_
+                          ("Process record ignores the memory change of instruction at address 0x%s because it can't get the value of the segment register.\n"),
+                          paddr_nz (i386_record_pc));
+      return (0);
+    }
 
-     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 (i386_record_lea_modrm_addr (&addr))
+    {
+      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.  */
+  if (record_arch_list_add_mem (addr, 1 << ot))
+    {
+      return (-1);
+    }
 
-  /* 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);
+  return (0);
+}
 
-  /* Use the SVR4 register numbering scheme for DWARF 2.  */
-  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_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_process_record (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  int prefixes = 0;
+  uint8_t tmpu8;
+  uint16_t tmpu16;
+  uint32_t tmpu32;
+  uint32_t opcode;
+
+  i386_record_pc = addr;
+  aflag = 1;
+  dflag = 1;
+  override = 0;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: i386_record pc = 0x%s\n",
+                         paddr_nz (i386_record_pc));
+    }
 
-  /* 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.  */
+  /* prefixes */
+  while (1)
+    {
+      if (target_read_memory (i386_record_pc, &tmpu8, 1))
+       {
+         if (record_debug)
+           {
+             printf_unfiltered (_
+                                ("Process record: error reading memory at addr 0x%s len = 1.\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_print_float_info (gdbarch, i387_print_float_info);
+  /* now check op code */
+  opcode = (uint32_t) tmpu8;
+reswitch:
+  switch (opcode)
+    {
+    case 0x0f:
+      if (target_read_memory (i386_record_pc, &tmpu8, 1))
+       {
+         if (record_debug)
+           {
+             printf_unfiltered (_
+                                ("Process record: error reading memory at addr 0x%s len = 1.\n"),
+                                paddr_nz (i386_record_pc));
+           }
+         return (-1);
+       }
+      i386_record_pc++;
+      opcode = (uint16_t) tmpu8 | 0x0f00;
+      goto reswitch;
+      break;
 
-  set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+      /* arith & logic */
+    case 0x00:
+    case 0x01:
+    case 0x02:
+    case 0x03:
+    case 0x04:
+    case 0x05:
+    case 0x08:
+    case 0x09:
+    case 0x0a:
+    case 0x0b:
+    case 0x0c:
+    case 0x0d:
+    case 0x10:
+    case 0x11:
+    case 0x12:
+    case 0x13:
+    case 0x14:
+    case 0x15:
+    case 0x18:
+    case 0x19:
+    case 0x1a:
+    case 0x1b:
+    case 0x1c:
+    case 0x1d:
+    case 0x20:
+    case 0x21:
+    case 0x22:
+    case 0x23:
+    case 0x24:
+    case 0x25:
+    case 0x28:
+    case 0x29:
+    case 0x2a:
+    case 0x2b:
+    case 0x2c:
+    case 0x2d:
+    case 0x30:
+    case 0x31:
+    case 0x32:
+    case 0x33:
+    case 0x34:
+    case 0x35:
+    case 0x38:
+    case 0x39:
+    case 0x3a:
+    case 0x3b:
+    case 0x3c:
+    case 0x3d:
+      if (((opcode >> 3) & 7) != OP_CMPL)
+       {
+         if ((opcode & 1) == 0)
+           {
+             ot = OT_BYTE;
+           }
+         else
+           {
+             ot = dflag + OT_WORD;
+           }
 
-  /* Call dummy code.  */
-  set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+         switch ((opcode >> 1) & 3)
+           {
+             /* OP Ev, Gv */
+           case 0:
+             if (i386_record_modrm ())
+               {
+                 return (-1);
+               }
+             if (mod != 3)
+               {
+                 if (i386_record_lea_modrm ())
+                   {
+                     return (-1);
+                   }
+               }
+             else
+               {
+                 if (ot == OT_BYTE)
+                   {
+                     rm &= 0x3;
+                   }
+                 if (record_arch_list_add_reg (rm))
+                   {
+                     return (-1);
+                   }
+               }
+             break;
+             /* OP Gv, Ev */
+           case 1:
+             if (i386_record_modrm ())
+               {
+                 return (-1);
+               }
+             if (ot == OT_BYTE)
+               {
+                 reg &= 0x3;
+               }
+             if (record_arch_list_add_reg (reg))
+               {
+                 return (-1);
+               }
+             break;
+             /* OP A, Iv */
+           case 2:
+             if (record_arch_list_add_reg (I386_EAX_REGNUM))
+               {
+                 return (-1);
+               }
+             break;
+           }
+       }
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* GRP1 */
+    case 0x80:
+    case 0x81:
+    case 0x82:
+    case 0x83:
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+
+      if (reg != OP_CMPL)
+       {
+         if ((opcode & 1) == 0)
+           {
+             ot = OT_BYTE;
+           }
+         else
+           {
+             ot = dflag + OT_WORD;
+           }
+
+         if (mod != 3)
+           {
+             if (i386_record_lea_modrm ())
+               {
+                 return (-1);
+               }
+           }
+         else
+           {
+             if (record_arch_list_add_reg (rm))
+               {
+                 return (-1);
+               }
+           }
+       }
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* inv */
+    case 0x40:
+    case 0x41:
+    case 0x42:
+    case 0x43:
+    case 0x44:
+    case 0x45:
+    case 0x46:
+    case 0x47:
+      /* dec */
+    case 0x48:
+    case 0x49:
+    case 0x4a:
+    case 0x4b:
+    case 0x4c:
+    case 0x4d:
+    case 0x4e:
+    case 0x4f:
+      if (record_arch_list_add_reg (opcode & 7))
+       {
+         return (-1);
+       }
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* GRP3 */
+    case 0xf6:
+    case 0xf7:
+      if ((opcode & 1) == 0)
+       {
+         ot = OT_BYTE;
+       }
+      else
+       {
+         ot = dflag + OT_WORD;
+       }
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+
+      switch (reg)
+       {
+         /* test */
+       case 0:
+         if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+           {
+             return (-1);
+           }
+         break;
+         /* not */
+       case 2:
+         if (mod != 3)
+           {
+             if (i386_record_lea_modrm ())
+               {
+                 return (-1);
+               }
+           }
+         else
+           {
+             if (ot == OT_BYTE)
+               {
+                 rm &= 0x3;
+               }
+             if (record_arch_list_add_reg (rm))
+               {
+                 return (-1);
+               }
+           }
+         break;
+         /* neg */
+       case 3:
+         if (mod != 3)
+           {
+             if (i386_record_lea_modrm ())
+               {
+                 return (-1);
+               }
+           }
+         else
+           {
+             if (ot == OT_BYTE)
+               {
+                 rm &= 0x3;
+               }
+             if (record_arch_list_add_reg (rm))
+               {
+                 return (-1);
+               }
+           }
+         if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+           {
+             return (-1);
+           }
+         break;
+         /* mul */
+       case 4:
+         /* imul */
+       case 5:
+         /* div */
+       case 6:
+         /* idiv */
+       case 7:
+         if (record_arch_list_add_reg (I386_EAX_REGNUM))
+           {
+             return (-1);
+           }
+         if (ot != OT_BYTE)
+           {
+             if (record_arch_list_add_reg (I386_EDX_REGNUM))
+               {
+                 return (-1);
+               }
+           }
+         if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+           {
+             return (-1);
+           }
+         break;
+       default:
+         i386_record_pc -= 2;
+         opcode = opcode << 8 | modrm;
+         goto no_support;
+         break;
+       }
+      break;
+
+      /* GRP4 */
+    case 0xfe:
+      /* GRP5 */
+    case 0xff:
+      if ((opcode & 1) == 0)
+       {
+         ot = OT_BYTE;
+       }
+      else
+       {
+         ot = dflag + OT_WORD;
+       }
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+      if (reg >= 2 && opcode == 0xfe)
+       {
+         i386_record_pc -= 2;
+         opcode = opcode << 8 | modrm;
+         goto no_support;
+       }
+
+      switch (reg)
+       {
+         /* inc */
+       case 0:
+         /* dec */
+       case 1:
+         if (mod != 3)
+           {
+             if (i386_record_lea_modrm ())
+               {
+                 return (-1);
+               }
+           }
+         else
+           {
+             if (ot == OT_BYTE)
+               {
+                 rm &= 0x3;
+               }
+             if (record_arch_list_add_reg (rm))
+               {
+                 return (-1);
+               }
+           }
+         if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+           {
+             return (-1);
+           }
+         break;
+         /* call */
+       case 2:
+         /* push */
+       case 6:
+         if (record_arch_list_add_reg (I386_ESP_REGNUM))
+           {
+             return (-1);
+           }
+         regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem
+             ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+           {
+             return (-1);
+           }
+         break;
+         /* lcall */
+       case 3:
+         if (record_arch_list_add_reg (I386_ESP_REGNUM))
+           {
+             return (-1);
+           }
+         if (record_arch_list_add_reg (I386_CS_REGNUM))
+           {
+             return (-1);
+           }
+         regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem
+             ((CORE_ADDR) tmpu32 - (1 << (dflag + 2)), (1 << (dflag + 2))))
+           {
+             return (-1);
+           }
+         break;
+         /* jmp */
+       case 4:
+         /* ljmp */
+       case 5:
+         break;
+       default:
+         i386_record_pc -= 2;
+         opcode = opcode << 8 | modrm;
+         goto no_support;
+         break;
+       }
+      break;
+
+      /* test */
+    case 0x84:
+    case 0x85:
+    case 0xa8:
+    case 0xa9:
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* CWDE/CBW */
+    case 0x98:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* CDQ/CWD */
+    case 0x99:
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+       {
+         return (-1);
+       }
+      if (record_arch_list_add_reg (I386_EDX_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* imul */
+    case 0x0faf:
+    case 0x69:
+    case 0x6b:
+      ot = dflag + OT_WORD;
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+      if (ot == OT_BYTE)
+       {
+         reg &= 0x3;
+       }
+      if (record_arch_list_add_reg (reg))
+       {
+         return (-1);
+       }
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* xadd */
+    case 0x0fc0:
+    case 0x0fc1:
+      if ((opcode & 1) == 0)
+       {
+         ot = OT_BYTE;
+       }
+      else
+       {
+         ot = dflag + OT_WORD;
+       }
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+      if (mod == 3)
+       {
+         if (ot == OT_BYTE)
+           {
+             reg &= 0x3;
+           }
+         if (record_arch_list_add_reg (reg))
+           {
+             return (-1);
+           }
+         if (ot == OT_BYTE)
+           {
+             rm &= 0x3;
+           }
+         if (record_arch_list_add_reg (rm))
+           {
+             return (-1);
+           }
+       }
+      else
+       {
+         if (i386_record_lea_modrm ())
+           {
+             return (-1);
+           }
+         if (ot == OT_BYTE)
+           {
+             reg &= 0x3;
+           }
+         if (record_arch_list_add_reg (reg))
+           {
+             return (-1);
+           }
+       }
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* cmpxchg */
+    case 0x0fb0:
+    case 0x0fb1:
+      if ((opcode & 1) == 0)
+       {
+         ot = OT_BYTE;
+       }
+      else
+       {
+         ot = dflag + OT_WORD;
+       }
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+      if (mod == 3)
+       {
+         if (record_arch_list_add_reg (I386_EAX_REGNUM))
+           {
+             return (-1);
+           }
+         if (ot == OT_BYTE)
+           {
+             reg &= 0x3;
+           }
+         if (record_arch_list_add_reg (reg))
+           {
+             return (-1);
+           }
+       }
+      else
+       {
+         if (record_arch_list_add_reg (I386_EAX_REGNUM))
+           {
+             return (-1);
+           }
+         if (i386_record_lea_modrm ())
+           {
+             return (-1);
+           }
+       }
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* cmpxchg8b */
+    case 0x0fc7:
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+      if (mod == 3)
+       {
+         i386_record_pc -= 2;
+         opcode = opcode << 8 | modrm;
+         goto no_support;
+       }
+      if (record_arch_list_add_reg (I386_EAX_REGNUM))
+       {
+         return (-1);
+       }
+      if (record_arch_list_add_reg (I386_EDX_REGNUM))
+       {
+         return (-1);
+       }
+      if (i386_record_lea_modrm ())
+       {
+         return (-1);
+       }
+      if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+       {
+         return (-1);
+       }
+      break;
+
+      /* push */
+    case 0x50:
+    case 0x51:
+    case 0x52:
+    case 0x53:
+    case 0x54:
+    case 0x55:
+    case 0x56:
+    case 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:
+    case 0x59:
+    case 0x5a:
+    case 0x5b:
+    case 0x5c:
+    case 0x5d:
+    case 0x5e:
+    case 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 (override)
+         {
+           if (record_debug)
+             printf_unfiltered (_
+                                ("Process record ignores the memory change of instruction at address 0x%s because it can't get the value of the segment register.\n"),
+                                paddr_nz (i386_record_pc));
+         }
+       else
+         {
+           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))
+                 {
+                   if (record_debug)
+                     {
+                       printf_unfiltered (_
+                                          ("Process record: error reading memory at addr 0x%s len = 4.\n"),
+                                          paddr_nz (i386_record_pc));
+                     }
+                   return (-1);
+                 }
+               i386_record_pc += 4;
+             }
+           else
+             {
+               if (target_read_memory
+                   (i386_record_pc, (gdb_byte *) & tmpu16, 4))
+                 {
+                   if (record_debug)
+                     {
+                       printf_unfiltered (_
+                                          ("Process record: error reading memory at addr 0x%s len = 4.\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:
+    case 0xb1:
+    case 0xb2:
+    case 0xb3:
+    case 0xb4:
+    case 0xb5:
+    case 0xb6:
+    case 0xb7:
+      if (record_arch_list_add_reg ((opcode & 0x7) & 0x3))
+       {
+         return (-1);
+       }
+      break;
+
+      /* mov R, Iv */
+    case 0xb8:
+    case 0xb9:
+    case 0xba:
+    case 0xbb:
+    case 0xbc:
+    case 0xbd:
+    case 0xbe:
+    case 0xbf:
+      if (record_arch_list_add_reg (opcode & 0x7))
+       {
+         return (-1);
+       }
+      break;
+
+      /* xchg R, EAX */
+    case 0x91:
+    case 0x92:
+    case 0x93:
+    case 0x94:
+    case 0x95:
+    case 0x96:
+    case 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 */
+      /* It just record the memory change of instrcution. */
+    case 0xd8:
+    case 0xd9:
+    case 0xda:
+    case 0xdb:
+    case 0xdc:
+    case 0xdd:
+    case 0xde:
+    case 0xdf:
+      if (i386_record_modrm ())
+       {
+         return (-1);
+       }
+      reg |= ((opcode & 7) << 3);
+      if (mod != 3)
+       {
+         /* memory */
+         uint32_t addr;
+
+         if (i386_record_lea_modrm_addr (&addr))
+           {
+             return (-1);
+           }
+         switch (reg)
+           {
+           case 0x00:
+           case 0x01:
+           case 0x02:
+           case 0x03:
+           case 0x04:
+           case 0x05:
+           case 0x06:
+           case 0x07:
+           case 0x10:
+           case 0x11:
+           case 0x12:
+           case 0x13:
+           case 0x14:
+           case 0x15:
+           case 0x16:
+           case 0x17:
+           case 0x20:
+           case 0x21:
+           case 0x22:
+           case 0x23:
+           case 0x24:
+           case 0x25:
+           case 0x26:
+           case 0x27:
+           case 0x30:
+           case 0x31:
+           case 0x32:
+           case 0x33:
+           case 0x34:
+           case 0x35:
+           case 0x36:
+           case 0x37:
+             break;
+           case 0x08:
+           case 0x0a:
+           case 0x0b:
+           case 0x18:
+           case 0x19:
+           case 0x1a:
+           case 0x1b:
+           case 0x28:
+           case 0x29:
+           case 0x2a:
+           case 0x2b:
+           case 0x38:
+           case 0x39:
+           case 0x3a:
+           case 0x3b:
+             switch (reg & 7)
+               {
+               case 0:
+                 break;
+               case 1:
+                 switch (reg >> 4)
+                   {
+                   case 0:
+                     if (record_arch_list_add_mem (addr, 4))
+                       {
+                         return (-1);
+                       }
+                     break;
+                   case 2:
+                     if (record_arch_list_add_mem (addr, 8))
+                       {
+                         return (-1);
+                       }
+                     break;
+                   case 3:
+                   default:
+                     if (record_arch_list_add_mem (addr, 2))
+                       {
+                         return (-1);
+                       }
+                     break;
+                   }
+                 break;
+               default:
+                 switch (reg >> 4)
+                   {
+                   case 0:
+                   case 1:
+                     if (record_arch_list_add_mem (addr, 4))
+                       {
+                         return (-1);
+                       }
+                     break;
+                   case 2:
+                     if (record_arch_list_add_mem (addr, 8))
+                       {
+                         return (-1);
+                       }
+                     break;
+                   case 3:
+                   default:
+                     if (record_arch_list_add_mem (addr, 2))
+                       {
+                         return (-1);
+                       }
+                     break;
+                   }
+                 break;
+               }
+             break;
+           case 0x0c:
+           case 0x0d:
+           case 0x1d:
+           case 0x2c:
+           case 0x3c:
+           case 0x3d:
+             break;
+           case 0x0e:
+             if (dflag)
+               {
+                 if (record_arch_list_add_mem (addr, 28))
+                   {
+                     return (-1);
+                   }
+               }
+             else
+               {
+                 if (record_arch_list_add_mem (addr, 14))
+                   {
+                     return (-1);
+                   }
+               }
+             break;
+           case 0x0f:
+           case 0x2f:
+             if (record_arch_list_add_mem (addr, 2))
+               {
+                 return (-1);
+               }
+             break;
+           case 0x1f:
+           case 0x3e:
+             if (record_arch_list_add_mem (addr, 10))
+               {
+                 return (-1);
+               }
+             break;
+           case 0x2e:
+             if (dflag)
+               {
+                 if (record_arch_list_add_mem (addr, 28))
+                   {
+                     return (-1);
+                   }
+                 addr += 28;
+               }
+             else
+               {
+                 if (record_arch_list_add_mem (addr, 14))
+                   {
+                     return (-1);
+                   }
+                 addr += 14;
+               }
+             if (record_arch_list_add_mem (addr, 80))
+               {
+                 return (-1);
+               }
+             break;
+           case 0x3f:
+             if (record_arch_list_add_mem (addr, 8))
+               {
+                 return (-1);
+               }
+             break;
+           default:
+             i386_record_pc -= 2;
+             opcode = opcode << 8 | modrm;
+             goto no_support;
+             break;
+           }
+       }
+      break;
+
+      /* 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; */
+            if (record_debug)
+             printf_unfiltered (_
+                                ("Process record ignores the memory change of instruction at address 0x%s because it can't get the value of the segment register.\n"),
+                          paddr_nz (i386_record_pc));
+         }
+
+       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 (aflag)
+             {
+               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 (aflag)
+             {
+               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:
+    case 0x71:
+    case 0x72:
+    case 0x73:
+    case 0x74:
+    case 0x75:
+    case 0x76:
+    case 0x77:
+    case 0x78:
+    case 0x79:
+    case 0x7a:
+    case 0x7b:
+    case 0x7c:
+    case 0x7d:
+    case 0x7e:
+    case 0x7f:
+      /* jcc Jv */
+    case 0x0f80:
+    case 0x0f81:
+    case 0x0f82:
+    case 0x0f83:
+    case 0x0f84:
+    case 0x0f85:
+    case 0x0f86:
+    case 0x0f87:
+    case 0x0f88:
+    case 0x0f89:
+    case 0x0f8a:
+    case 0x0f8b:
+    case 0x0f8c:
+    case 0x0f8d:
+    case 0x0f8e:
+    case 0x0f8f:
+      break;
+
+      /* setcc Gv */
+    case 0x0f90:
+    case 0x0f91:
+    case 0x0f92:
+    case 0x0f93:
+    case 0x0f94:
+    case 0x0f95:
+    case 0x0f96:
+    case 0x0f97:
+    case 0x0f98:
+    case 0x0f99:
+    case 0x0f9a:
+    case 0x0f9b:
+    case 0x0f9c:
+    case 0x0f9d:
+    case 0x0f9e:
+    case 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:
+    case 0x0f41:
+    case 0x0f42:
+    case 0x0f43:
+    case 0x0f44:
+    case 0x0f45:
+    case 0x0f46:
+    case 0x0f47:
+    case 0x0f48:
+    case 0x0f49:
+    case 0x0f4a:
+    case 0x0f4b:
+    case 0x0f4c:
+    case 0x0f4d:
+    case 0x0f4e:
+    case 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 (_
+                        ("Process record doesn't support instruction fwait.\n"));
+      i386_record_pc -= 1;
+      goto no_support;
+      break;
+
+      /* int3 */
+      /* XXX */
+    case 0xcc:
+      printf_unfiltered (_
+                        ("Process record doesn'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))
+         {
+           if (record_debug)
+             {
+               printf_unfiltered (_
+                                  ("Process record: error reading memory at addr 0x%s len = 1.\n"),
+                                  paddr_nz (i386_record_pc));
+             }
+           return (-1);
+         }
+       i386_record_pc++;
+       if (tmpu8 != 0x80
+           || gdbarch_tdep (gdbarch)->i386_intx80_record == NULL)
+         {
+           printf_unfiltered (_
+                              ("Process record doesn'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 (_
+                        ("Process record doesn'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 (_
+                        ("Process record doesn't support instruction bound.\n"));
+      i386_record_pc -= 1;
+      goto no_support;
+      break;
+
+      /* bswap reg */
+    case 0x0fc8:
+    case 0x0fc9:
+    case 0x0fca:
+    case 0x0fcb:
+    case 0x0fcc:
+    case 0x0fcd:
+    case 0x0fce:
+    case 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 (_
+                        ("Process record doesn't support instruction wrmsr.\n"));
+      i386_record_pc -= 2;
+      goto no_support;
+      break;
+
+      /* rdmsr */
+    case 0x0f32:
+      printf_unfiltered (_
+                        ("Process record doesn't support instruction rdmsr.\n"));
+      i386_record_pc -= 2;
+      goto no_support;
+      break;
+
+      /* rdtsc */
+    case 0x0f31:
+      printf_unfiltered (_
+                        ("Process record doesn'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 (_
+                              ("Process record doesn'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 (_
+                        ("Process record doesn'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 (_
+                        ("Process record doesn'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)
+             {
+               if (record_debug)
+                 printf_unfiltered (_
+                                    ("Process record ignores the memory change of instruction at address 0x%s because it can't get the value of the segment register.\n"),
+                                    paddr_nz (i386_record_pc));
+error("3");
+             }
+           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)
+               {
+                 if (record_debug)
+                   printf_unfiltered (_
+                                      ("Process record ignores the memory change of instruction at address 0x%s because it can't get the value of the segment register.\n"),
+                                      paddr_nz (i386_record_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:
+    case 0x0f1a:
+    case 0x0f1b:
+    case 0x0f1c:
+    case 0x0f1d:
+    case 0x0f1e:
+    case 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 (_
+                    ("Process record doesn't support instruction 0x%02x at address 0x%s.\n"),
+                    (unsigned int) (opcode), paddr_nz (i386_record_pc));
+  return (-1);
+}
+
+\f
+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 2.  */
+  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);
@@ -2829,6 +5791,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_skip_permanent_breakpoint (gdbarch,
                                         i386_skip_permanent_breakpoint);
 
+  set_gdbarch_process_record (gdbarch, i386_process_record);
+
   return gdbarch;
 }
 
index d1366b68b250c653fba2ce3627bd8fbf7ae64ac1..a5ba588352c455bcbd5a88a9368f08346dd0a830 100644 (file)
@@ -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.  */
index eb2528ce7b9d771bf431f2b5f13185396645ddf0..95022a28daf27a282328a63319b61ad0362458d9 100644 (file)
@@ -50,6 +50,8 @@
 #include "mi/mi-common.h"
 #include "event-top.h"
 
+#include "record.h"
+
 /* Prototypes for local functions */
 
 static void signals_info (char *, int);
@@ -604,7 +606,8 @@ use_displaced_stepping (struct gdbarch *gdbarch)
   return (((can_use_displaced_stepping == can_use_displaced_stepping_auto
            && non_stop)
           || can_use_displaced_stepping == can_use_displaced_stepping_on)
-         && gdbarch_displaced_step_copy_insn_p (gdbarch));
+         && gdbarch_displaced_step_copy_insn_p (gdbarch)
+         && !RECORD_IS_USED);
 }
 
 /* Clean out any stray displaced stepping state.  */
@@ -1309,6 +1312,12 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
   if (step < 0)
     stop_after_trap = 1;
 
+   /* When GDB resume the inferior, process record target doesn't need to
+      record the memory and register store operation of GDB. So set
+      record_not_record to 1. */
+  if (RECORD_IS_USED)
+    record_not_record_set ();
+
   if (addr == (CORE_ADDR) -1)
     {
       if (pc == stop_pc && breakpoint_here_p (pc) 
diff --git a/gdb/linux-record.c b/gdb/linux-record.c
new file mode 100644 (file)
index 0000000..b5dae50
--- /dev/null
@@ -0,0 +1,2507 @@
+/* Process record and replay target code for GNU/Linux.
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "target.h"
+#include "regcache.h"
+#include "record.h"
+#include "linux-record.h"
+#include <stdint.h>
+
+/* 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 RECORD_PTRACE_PEEKTEXT 1
+#define RECORD_PTRACE_PEEKDATA 2
+#define RECORD_PTRACE_PEEKUSR  3
+
+/* 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 RECORD_SYS_SOCKET      1
+#define RECORD_SYS_BIND                2
+#define RECORD_SYS_CONNECT     3
+#define RECORD_SYS_LISTEN      4
+#define RECORD_SYS_ACCEPT      5
+#define RECORD_SYS_GETSOCKNAME 6
+#define RECORD_SYS_GETPEERNAME 7
+#define RECORD_SYS_SOCKETPAIR  8
+#define RECORD_SYS_SEND                9
+#define RECORD_SYS_RECV                10
+#define RECORD_SYS_SENDTO      11
+#define RECORD_SYS_RECVFROM    12
+#define RECORD_SYS_SHUTDOWN    13
+#define RECORD_SYS_SETSOCKOPT  14
+#define RECORD_SYS_GETSOCKOPT  15
+#define RECORD_SYS_SENDMSG     16
+#define 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 RECORD_SEMOP           1
+#define RECORD_SEMGET          2
+#define RECORD_SEMCTL          3
+#define RECORD_SEMTIMEDOP      4
+#define RECORD_MSGSND          11
+#define RECORD_MSGRCV          12
+#define RECORD_MSGGET          13
+#define RECORD_MSGCTL          14
+#define RECORD_SHMAT           21
+#define RECORD_SHMDT           22
+#define RECORD_SHMGET          23
+#define 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 RECORD_Q_GETFMT                0x800004
+#define RECORD_Q_GETINFO       0x800005
+#define RECORD_Q_GETQUOTA      0x800007
+#define RECORD_Q_XGETQSTAT     (('5'<<8)+(5))
+#define RECORD_Q_XGETQUOTA     (('3'<<8)+(3))
+
+/* When the architecture process record get a Linux syscall instruction, it
+   will get a Linux syscall number of this architecture and convert it to the
+   Linux syscall number "num" which is internal to GDB.
+   Most Linux syscalls across architectures in Linux would be similar and
+   mostly differ by sizes of types and structures.  This sizes are put
+   to "tdep".
+   Record the values of the registers and memory that will be changed in
+   current system call.
+   Return -1 if something wrong.  */
+
+int
+record_linux_system_call (int num, linux_record_tdep_t * tdep)
+{
+  uint32_t tmpu32;
+
+  switch (num)
+    {
+      /* sys_restart_syscall */
+    case 0:
+      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 stop 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, tdep->arg2, (gdb_byte *) & addr);
+       regcache_raw_read (record_regcache, tdep->arg3, (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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32 == RECORD_PTRACE_PEEKTEXT
+         || tmpu32 == RECORD_PTRACE_PEEKDATA
+         || tmpu32 == RECORD_PTRACE_PEEKUSR)
+       {
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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 there need add a lot of support of other ioctl requests.  */
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32 == tdep->ioctl_FIOCLEX || tmpu32 == tdep->ioctl_FIONCLEX
+         || tmpu32 == tdep->ioctl_FIONBIO || tmpu32 == tdep->ioctl_FIOASYNC
+         || tmpu32 == tdep->ioctl_TCSETS || tmpu32 == tdep->ioctl_TCSETSW
+         || tmpu32 == tdep->ioctl_TCSETSF || tmpu32 == tdep->ioctl_TCSETA
+         || tmpu32 == tdep->ioctl_TCSETAW || tmpu32 == tdep->ioctl_TCSETAF
+         || tmpu32 == tdep->ioctl_TCSBRK || tmpu32 == tdep->ioctl_TCXONC
+         || tmpu32 == tdep->ioctl_TCFLSH || tmpu32 == tdep->ioctl_TIOCEXCL
+         || tmpu32 == tdep->ioctl_TIOCNXCL
+         || tmpu32 == tdep->ioctl_TIOCSCTTY
+         || tmpu32 == tdep->ioctl_TIOCSPGRP || tmpu32 == tdep->ioctl_TIOCSTI
+         || tmpu32 == tdep->ioctl_TIOCSWINSZ
+         || tmpu32 == tdep->ioctl_TIOCMBIS || tmpu32 == tdep->ioctl_TIOCMBIC
+         || tmpu32 == tdep->ioctl_TIOCMSET
+         || tmpu32 == tdep->ioctl_TIOCSSOFTCAR
+         || tmpu32 == tdep->ioctl_TIOCCONS
+         || tmpu32 == tdep->ioctl_TIOCSSERIAL
+         || tmpu32 == tdep->ioctl_TIOCPKT || tmpu32 == tdep->ioctl_TIOCNOTTY
+         || tmpu32 == tdep->ioctl_TIOCSETD || tmpu32 == tdep->ioctl_TCSBRKP
+         || tmpu32 == tdep->ioctl_TIOCTTYGSTRUCT
+         || tmpu32 == tdep->ioctl_TIOCSBRK || tmpu32 == tdep->ioctl_TIOCCBRK
+         || tmpu32 == tdep->ioctl_TCSETS2 || tmpu32 == tdep->ioctl_TCSETSW2
+         || tmpu32 == tdep->ioctl_TCSETSF2
+         || tmpu32 == tdep->ioctl_TIOCSPTLCK
+         || tmpu32 == tdep->ioctl_TIOCSERCONFIG
+         || tmpu32 == tdep->ioctl_TIOCSERGWILD
+         || tmpu32 == tdep->ioctl_TIOCSERSWILD
+         || tmpu32 == tdep->ioctl_TIOCSLCKTRMIOS
+         || tmpu32 == tdep->ioctl_TIOCSERGETMULTI
+         || tmpu32 == tdep->ioctl_TIOCSERSETMULTI
+         || tmpu32 == tdep->ioctl_TIOCMIWAIT
+         || tmpu32 == tdep->ioctl_TIOCSHAYESESP)
+       {
+         /* Nothing to do.  */
+       }
+      else if (tmpu32 == tdep->ioctl_TCGETS || tmpu32 == tdep->ioctl_TCGETA
+              || tmpu32 == tdep->ioctl_TIOCGLCKTRMIOS)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_termios))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCGPGRP
+              || tmpu32 == tdep->ioctl_TIOCGSID)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_pid_t))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCOUTQ
+              || tmpu32 == tdep->ioctl_TIOCMGET
+              || tmpu32 == tdep->ioctl_TIOCGSOFTCAR
+              || tmpu32 == tdep->ioctl_FIONREAD
+              || tmpu32 == tdep->ioctl_TIOCINQ
+              || tmpu32 == tdep->ioctl_TIOCGETD
+              || tmpu32 == tdep->ioctl_TIOCGPTN
+              || tmpu32 == tdep->ioctl_TIOCSERGETLSR)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCGWINSZ)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_winsize))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCLINUX)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_char))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCGSERIAL)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_serial_struct))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TCGETS2)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_termios2))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_FIOQSIZE)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_loff_t))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCGICOUNT)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem
+             (tmpu32, tdep->size_serial_icounter_struct))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCGHAYESESP)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_hayes_esp_config))
+           {
+             return (-1);
+           }
+       }
+      else if (tmpu32 == tdep->ioctl_TIOCSERGSTRUCT)
+       {
+         printf_unfiltered (_
+                            ("Process record and replay target doesn't support ioctl request TIOCSERGSTRUCT\n"));
+         return (1);
+       }
+      else
+       {
+         printf_unfiltered (_
+                            ("Process record and replay target doesn't support ioctl request 0x%08x.\n"),
+                            tmpu32);
+         return (1);
+       }
+      break;
+
+      /* sys_fcntl */
+    case 55:
+      /* XXX */
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+    sys_fcntl:
+      if (tmpu32 == F_GETLK)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_oldold_utsname))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_umask */
+    case 60:
+      /* sys_chroot */
+    case 61:
+      break;
+
+      /* sys_ustat */
+    case 62:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_rlimit))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_getrusage */
+    case 77:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_rusage))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_gettimeofday */
+    case 78:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timeval))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timezone))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_settimeofday */
+    case 79:
+      break;
+
+      /* sys_getgroups16 */
+    case 80:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_old_gid_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_setgroups16 */
+    case 81:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_old_gid_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* old_select */
+    case 82:
+      {
+       struct sel_arg_struct
+       {
+         CORE_ADDR n;
+         CORE_ADDR inp;
+         CORE_ADDR outp;
+         CORE_ADDR exp;
+         CORE_ADDR tvp;
+       } sel;
+
+       regcache_raw_read (record_regcache, tdep->arg1,
+                          (gdb_byte *) & tmpu32);
+       if (tmpu32)
+         {
+           if (target_read_memory (tmpu32, (gdb_byte *) & sel, sizeof (sel)))
+             {
+               if (record_debug)
+                 {
+                   fprintf_unfiltered (gdb_stdlog,
+                                       "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                       paddr_nz (tmpu32), sizeof (sel));
+                 }
+               return (-1);
+             }
+           if (record_arch_list_add_mem (sel.inp, tdep->size_fd_set))
+             {
+               return (-1);
+             }
+           if (record_arch_list_add_mem (sel.outp, tdep->size_fd_set))
+             {
+               return (-1);
+             }
+           if (record_arch_list_add_mem (sel.exp, tdep->size_fd_set))
+             {
+               return (-1);
+             }
+           if (record_arch_list_add_mem (sel.tvp, tdep->size_timeval))
+             {
+               return (-1);
+             }
+         }
+      }
+      break;
+
+      /* sys_symlink */
+    case 83:
+      break;
+
+      /* sys_readlink */
+    case 85:
+      {
+       uint32_t len;
+       regcache_raw_read (record_regcache, tdep->arg2,
+                          (gdb_byte *) & tmpu32);
+       regcache_raw_read (record_regcache, tdep->arg3, (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 stop the program?"));
+       target_terminal_inferior ();
+       if (q)
+         {
+           return (1);
+         }
+      }
+      break;
+
+      /* old_readdir */
+    case 89:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_dirent))
+       {
+         return (-1);
+       }
+      break;
+
+      /* old_mmap */
+    case 90:
+      break;
+
+      /* sys_munmap */
+    case 91:
+      {
+       int q;
+       uint32_t len;
+
+       regcache_raw_read (record_regcache, tdep->arg1,
+                          (gdb_byte *) & tmpu32);
+       regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & len);
+       target_terminal_ours ();
+       q =
+         yquery (_
+                 ("The next instruction is syscall munmap.  It will free the memory addr = 0x%s len = %d.  It will make record target get error.  Do you want to stop 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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_statfs))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_ioperm */
+    case 101:
+      break;
+
+      /* sys_socketcall */
+    case 102:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+       {
+       case RECORD_SYS_SOCKET:
+       case RECORD_SYS_BIND:
+       case RECORD_SYS_CONNECT:
+       case RECORD_SYS_LISTEN:
+         break;
+       case RECORD_SYS_ACCEPT:
+       case RECORD_SYS_GETSOCKNAME:
+       case RECORD_SYS_GETPEERNAME:
+         {
+           uint32_t a[3];
+           regcache_raw_read (record_regcache, tdep->arg2,
+                              (gdb_byte *) & tmpu32);
+           if (tmpu32)
+             {
+               if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+                 {
+                   if (record_debug)
+                     {
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                           paddr_nz (tmpu32), sizeof (a));
+                     }
+                   return (-1);
+                 }
+               if (record_arch_list_add_mem (a[1], tdep->size_sockaddr))
+                 {
+                   return (-1);
+                 }
+               if (record_arch_list_add_mem (a[2], tdep->size_int))
+                 {
+                   return (-1);
+                 }
+             }
+         }
+         break;
+
+       case RECORD_SYS_SOCKETPAIR:
+         {
+           uint32_t a[4];
+           regcache_raw_read (record_regcache, tdep->arg2,
+                              (gdb_byte *) & tmpu32);
+           if (tmpu32)
+             {
+               if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+                 {
+                   if (record_debug)
+                     {
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                           paddr_nz (tmpu32), sizeof (a));
+                     }
+                   return (-1);
+                 }
+               if (record_arch_list_add_mem (a[3], tdep->size_int))
+                 {
+                   return (-1);
+                 }
+             }
+         }
+         break;
+       case RECORD_SYS_SEND:
+       case RECORD_SYS_SENDTO:
+         break;
+       case RECORD_SYS_RECV:
+         {
+           uint32_t a[3];
+           regcache_raw_read (record_regcache, tdep->arg2,
+                              (gdb_byte *) & tmpu32);
+           if (tmpu32)
+             {
+               if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+                 {
+                   if (record_debug)
+                     {
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                           paddr_nz (tmpu32), sizeof (a));
+                     }
+                   return (-1);
+                 }
+               if (a[2])
+                 {
+                   if (target_read_memory
+                       (a[2], (gdb_byte *) & (a[2]), sizeof (a[2])))
+                     {
+                       if (record_debug)
+                         {
+                           fprintf_unfiltered (gdb_stdlog,
+                                               "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                               paddr_nz (a[2]), sizeof (a[2]));
+                         }
+                       return (-1);
+                     }
+                   if (record_arch_list_add_mem (a[1], a[2]))
+                     {
+                       return (-1);
+                     }
+                 }
+             }
+         }
+         break;
+       case RECORD_SYS_RECVFROM:
+         {
+           uint32_t a[6];
+           regcache_raw_read (record_regcache, tdep->arg2,
+                              (gdb_byte *) & tmpu32);
+           if (tmpu32)
+             {
+               if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+                 {
+                   if (record_debug)
+                     {
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                           paddr_nz (tmpu32), sizeof (a));
+                     }
+                   return (-1);
+                 }
+               if (a[2])
+                 {
+                   if (target_read_memory
+                       (a[2], (gdb_byte *) & (a[2]), sizeof (a[2])))
+                     {
+                       if (record_debug)
+                         {
+                           fprintf_unfiltered (gdb_stdlog,
+                                               "Process record: error reading memory at addr = 0x%s len = %d.\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], tdep->size_sockaddr))
+                     {
+                       return (-1);
+                     }
+                   if (record_arch_list_add_mem (a[5], tdep->size_int))
+                     {
+                       return (-1);
+                     }
+                 }
+             }
+         }
+         break;
+       case RECORD_SYS_SHUTDOWN:
+       case RECORD_SYS_SETSOCKOPT:
+         break;
+       case RECORD_SYS_GETSOCKOPT:
+         {
+           uint32_t a[5];
+           uint32_t av;
+
+           regcache_raw_read (record_regcache, tdep->arg2,
+                              (gdb_byte *) & tmpu32);
+           if (tmpu32)
+             {
+               if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+                 {
+                   if (record_debug)
+                     {
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                           paddr_nz (tmpu32), sizeof (a));
+                     }
+                   return (-1);
+                 }
+               if (a[4])
+                 {
+                   if (target_read_memory
+                       (a[4], (gdb_byte *) & av, sizeof (av)))
+                     {
+                       if (record_debug)
+                         {
+                           fprintf_unfiltered (gdb_stdlog,
+                                               "Process record: error reading memory at addr = 0x%s len = %d.\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], tdep->size_int))
+                     {
+                       return (-1);
+                     }
+                 }
+             }
+         }
+         break;
+       case RECORD_SYS_SENDMSG:
+         break;
+       case 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, tdep->arg2,
+                              (gdb_byte *) & tmpu32);
+           if (tmpu32)
+             {
+               if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+                 {
+                   if (record_debug)
+                     {
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                           paddr_nz (tmpu32), sizeof (a));
+                     }
+                   return (-1);
+                 }
+               if (record_arch_list_add_mem (a[1], tdep->size_msghdr))
+                 {
+                   return (-1);
+                 }
+               if (a[1])
+                 {
+                   if (target_read_memory
+                       (a[1], (gdb_byte *) & rec, sizeof (rec)))
+                     {
+                       if (record_debug)
+                         {
+                           fprintf_unfiltered (gdb_stdlog,
+                                               "Process record: error reading memory at addr = 0x%s len = %d.\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)))
+                             {
+                               if (record_debug)
+                                 {
+                                   fprintf_unfiltered (gdb_stdlog,
+                                                       "Process record: error reading memory at addr = 0x%s len = %d.\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 (_
+                            ("Process record and replay target doesn'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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_itimerval))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_getitimer */
+    case 105:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_itimerval))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_newstat */
+    case 106:
+      /* sys_newlstat */
+    case 107:
+      /* sys_newfstat */
+    case 108:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_stat))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_uname */
+    case 109:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_rusage))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_swapoff */
+    case 115:
+      break;
+
+      /* sys_sysinfo */
+    case 116:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_sysinfo))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_ipc */
+    case 117:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+       {
+       case RECORD_MSGRCV:
+         {
+           int32_t second;
+           uint32_t ptr;
+           regcache_raw_read (record_regcache, tdep->arg3,
+                              (gdb_byte *) & second);
+           regcache_raw_read (record_regcache, tdep->arg5,
+                              (gdb_byte *) & ptr);
+           if (record_arch_list_add_mem (ptr, second + tdep->size_long))
+             {
+               return (-1);
+             }
+         }
+         break;
+       case RECORD_MSGCTL:
+         regcache_raw_read (record_regcache, tdep->arg5,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_msqid_ds))
+           {
+             return (-1);
+           }
+         break;
+       case RECORD_SHMAT:
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_ulong))
+           {
+             return (-1);
+           }
+         break;
+       case RECORD_SHMCTL:
+         regcache_raw_read (record_regcache, tdep->arg5,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_new_utsname))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_modify_ldt */
+    case 123:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32 == 0 || tmpu32 == 2)
+       {
+         uint32_t ptr, bytecount;
+         regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & ptr);
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & bytecount);
+         if (record_arch_list_add_mem (ptr, bytecount))
+           {
+             return (-1);
+           }
+       }
+      break;
+
+      /* sys_adjtimex */
+    case 124:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timex))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_mprotect */
+    case 125:
+      break;
+
+      /* sys_sigprocmask */
+    case 126:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+       {
+       case RECORD_Q_GETFMT:
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, 4))
+           {
+             return (-1);
+           }
+         break;
+       case RECORD_Q_GETINFO:
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_mem_dqinfo))
+           {
+             return (-1);
+           }
+         break;
+       case RECORD_Q_GETQUOTA:
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_if_dqblk))
+           {
+             return (-1);
+           }
+         break;
+       case RECORD_Q_XGETQSTAT:
+       case RECORD_Q_XGETQUOTA:
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32 == 2)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (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, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_loff_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_getdents */
+    case 141:
+      {
+       uint32_t count;
+       regcache_raw_read (record_regcache, tdep->arg2,
+                          (gdb_byte *) & tmpu32);
+       regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & count);
+       if (record_arch_list_add_mem (tmpu32, tdep->size_dirent * count))
+         {
+           return (-1);
+         }
+      }
+      break;
+
+      /* sys_select */
+    case 142:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_fd_set))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_fd_set))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_fd_set))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg5, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & vec);
+       if (vec)
+         {
+           regcache_raw_read (record_regcache, tdep->arg3,
+                              (gdb_byte *) & vlen);
+           for (tmpu32 = 0; tmpu32 < vlen; tmpu32++)
+             {
+               if (target_read_memory
+                   (vec, (gdb_byte *) & iov, sizeof (struct record_iovec)))
+                 {
+                   if (record_debug)
+                     {
+                       fprintf_unfiltered (gdb_stdlog,
+                                           "Process record: error reading memory at addr = 0x%s len = %d.\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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timespec))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_mremap */
+    case 163:
+      /* sys_setresuid16 */
+    case 164:
+      break;
+
+      /* sys_getresuid16 */
+    case 165:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_old_uid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_old_uid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t nfds;
+         regcache_raw_read (record_regcache, tdep->arg2,
+                            (gdb_byte *) & nfds);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_pollfd * nfds))
+           {
+             return (-1);
+           }
+       }
+      break;
+
+      /* sys_nfsservctl */
+    case 169:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32 == 7 || tmpu32 == 8)
+       {
+         uint32_t rsize;
+         if (tmpu32 == 7)
+           {
+             rsize = tdep->size_NFS_FHSIZE;
+           }
+         else
+           {
+             rsize = tdep->size_knfsd_fh;
+           }
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_old_gid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_old_gid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_old_gid_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_prctl */
+    case 172:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+       {
+       case 2:
+         regcache_raw_read (record_regcache, tdep->arg2,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+           {
+             return (-1);
+           }
+         break;
+       case 16:
+         regcache_raw_read (record_regcache, tdep->arg2,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_TASK_COMM_LEN))
+           {
+             return (-1);
+           }
+         break;
+       }
+      break;
+
+      /* sys_rt_sigreturn */
+    case 173:
+      break;
+
+      /* sys_rt_sigaction */
+    case 174:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_sigaction))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_rt_sigprocmask */
+    case 175:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_sigset_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_rt_sigpending */
+    case 176:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t sigsetsize;
+         regcache_raw_read (record_regcache, tdep->arg2,
+                            (gdb_byte *) & sigsetsize);
+         if (record_arch_list_add_mem (tmpu32, sigsetsize))
+           {
+             return (-1);
+           }
+       }
+      break;
+
+      /* sys_rt_sigtimedwait */
+    case 177:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t count;
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t size;
+         regcache_raw_read (record_regcache, tdep->arg2,
+                            (gdb_byte *) & size);
+         if (record_arch_list_add_mem (tmpu32, size))
+           {
+             return (-1);
+           }
+       }
+      break;
+
+      /* sys_capget */
+    case 184:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_cap_user_data_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_capset */
+    case 185:
+      break;
+
+      /* sys_sigaltstack */
+    case 186:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_stack_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_sendfile */
+    case 187:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         int gidsetsize;
+         regcache_raw_read (record_regcache, tdep->arg1,
+                            (gdb_byte *) & gidsetsize);
+         if (record_arch_list_add_mem
+             (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_uid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_uid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_uid_t))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_setresgid */
+    case 210:
+      break;
+
+      /* sys_getresgid */
+    case 211:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_gid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_gid_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_PAGE_SIZE))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_madvise */
+    case 219:
+      break;
+
+      /* sys_getdents64 */
+    case 220:
+      {
+       uint32_t count;
+       regcache_raw_read (record_regcache, tdep->arg2,
+                          (gdb_byte *) & tmpu32);
+       regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & count);
+       if (record_arch_list_add_mem (tmpu32, tdep->size_dirent64 * count))
+         {
+           return (-1);
+         }
+      }
+      break;
+
+      /* sys_fcntl64 */
+    case 221:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      switch (tmpu32)
+       {
+       case F_GETLK64:
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t size;
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t size;
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t len;
+         regcache_raw_read (record_regcache, tdep->arg2, (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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_get_thread_area */
+    case 244:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_user_desc))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_io_setup */
+    case 245:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_long))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_io_destroy */
+    case 246:
+      break;
+
+      /* sys_io_getevents */
+    case 247:
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         int32_t nr;
+         regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & nr);
+         if (record_arch_list_add_mem (tmpu32, nr * tdep->size_io_event))
+           {
+             return (-1);
+           }
+       }
+      break;
+
+      /* sys_io_submit */
+    case 248:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         int32_t i, nr;
+         uint32_t *iocbp;
+         regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & nr);
+         iocbp = (uint32_t *) alloca (nr * tdep->size_int);
+         if (target_read_memory
+             (tmpu32, (gdb_byte *) iocbp, nr * tdep->size_int))
+           {
+             if (record_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                                     paddr_nz (tmpu32), nr * tdep->size_int);
+               }
+             return (-1);
+           }
+         for (i = 0; i < nr; i++)
+           {
+             if (record_arch_list_add_mem (iocbp[i], tdep->size_iocb))
+               {
+                 return (-1);
+               }
+           }
+       }
+      break;
+
+      /* sys_io_cancel */
+    case 249:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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 stop the program?"));
+       target_terminal_inferior ();
+       if (q)
+         {
+           return (1);
+         }
+      }
+      break;
+
+      /* sys_lookup_dcookie */
+    case 253:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t len;
+         regcache_raw_read (record_regcache, tdep->arg3, (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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         int32_t maxevents;
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & maxevents);
+         if (record_arch_list_add_mem
+             (tmpu32, maxevents * tdep->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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_timer_settime */
+    case 260:
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_itimerspec))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_timer_gettime */
+    case 261:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timespec))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_clock_getres */
+    case 266:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timespec))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_clock_nanosleep */
+    case 267:
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timespec))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_statfs64 */
+    case 268:
+      /* sys_fstatfs64 */
+    case 269:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t maxnode;
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & maxnode);
+         if (record_arch_list_add_mem (tmpu32, maxnode * tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t msg_len;
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & msg_len);
+         if (record_arch_list_add_mem (tmpu32, msg_len))
+           {
+             return (-1);
+           }
+       }
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_mq_notify */
+    case 281:
+      break;
+
+      /* sys_mq_getsetattr */
+    case 282:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_mq_attr))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_kexec_load */
+    case 283:
+      break;
+
+      /* sys_waitid */
+    case 284:
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_siginfo))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg5, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32 == 6 || tmpu32 == 11)
+       {
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & tmpu32);
+         if (tmpu32)
+           {
+             uint32_t buflen;
+             regcache_raw_read (record_regcache, tdep->arg4,
+                                (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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         int32_t bufsiz;
+         regcache_raw_read (record_regcache, tdep->arg4,
+                            (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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_fd_set))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_fd_set))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_fd_set))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg5, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_timespec))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_ppoll */
+    case 309:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t nfds;
+         regcache_raw_read (record_regcache, tdep->arg2,
+                            (gdb_byte *) & nfds);
+         if (record_arch_list_add_mem (tmpu32, tdep->size_pollfd * nfds))
+           {
+             return (-1);
+           }
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_splice */
+    case 313:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_loff_t))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg4, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->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, tdep->arg5, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         uint32_t nr_pages;
+         regcache_raw_read (record_regcache, tdep->arg2,
+                            (gdb_byte *) & nr_pages);
+         if (record_arch_list_add_mem (tmpu32, nr_pages * tdep->size_int))
+           {
+             return (-1);
+           }
+       }
+      break;
+
+      /* sys_getcpu */
+    case 318:
+      regcache_raw_read (record_regcache, tdep->arg1, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_int))
+       {
+         return (-1);
+       }
+      regcache_raw_read (record_regcache, tdep->arg3, (gdb_byte *) & tmpu32);
+      if (record_arch_list_add_mem (tmpu32, tdep->size_ulong * 2))
+       {
+         return (-1);
+       }
+      break;
+
+      /* sys_epoll_pwait */
+    case 319:
+      regcache_raw_read (record_regcache, tdep->arg2, (gdb_byte *) & tmpu32);
+      if (tmpu32)
+       {
+         int32_t maxevents;
+         regcache_raw_read (record_regcache, tdep->arg3,
+                            (gdb_byte *) & maxevents);
+         if (record_arch_list_add_mem
+             (tmpu32, maxevents * tdep->size_epoll_event))
+           {
+             return (-1);
+           }
+       }
+      break;
+
+    default:
+      printf_unfiltered (_
+                        ("Process record and replay target doesn't support syscall number 0x%08x\n"),
+                        tmpu32);
+      return (-1);
+      break;
+    }
+
+  return (0);
+}
diff --git a/gdb/linux-record.h b/gdb/linux-record.h
new file mode 100644 (file)
index 0000000..b0dd048
--- /dev/null
@@ -0,0 +1,171 @@
+/* Process record and replay target code for GNU/Linux.
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 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 _LINUX_RECORD_H_
+#define _LINUX_RECORD_H_
+
+typedef struct linux_record_tdep_s
+{
+  /* The size of the type that will be use in system call.  */
+  int size__old_kernel_stat;
+  int size_tms;
+  int size_loff_t;
+  int size_flock;
+  int size_oldold_utsname;
+  int size_ustat;
+  int size_old_sigaction;
+  int size_old_sigset_t;
+  int size_rlimit;
+  int size_rusage;
+  int size_timeval;
+  int size_timezone;
+  int size_old_gid_t;
+  int size_old_uid_t;
+  int size_fd_set;
+  int size_dirent;
+  int size_dirent64;
+  int size_statfs;
+  int size_statfs64;
+  int size_sockaddr;
+  int size_int;
+  int size_long;
+  int size_ulong;
+  int size_msghdr;
+  int size_itimerval;
+  int size_stat;
+  int size_old_utsname;
+  int size_sysinfo;
+  int size_msqid_ds;
+  int size_shmid_ds;
+  int size_new_utsname;
+  int size_timex;
+  int size_mem_dqinfo;
+  int size_if_dqblk;
+  int size_fs_quota_stat;
+  int size_timespec;
+  int size_pollfd;
+  int size_NFS_FHSIZE;
+  int size_knfsd_fh;
+  int size_TASK_COMM_LEN;
+  int size_sigaction;
+  int size_sigset_t;
+  int size_siginfo_t;
+  int size_cap_user_data_t;
+  int size_stack_t;
+  int size_off_t;
+  int size_stat64;
+  int size_gid_t;
+  int size_uid_t;
+  int size_PAGE_SIZE;
+  int size_flock64;
+  int size_user_desc;
+  int size_io_event;
+  int size_iocb;
+  int size_epoll_event;
+  int size_itimerspec;
+  int size_mq_attr;
+  int size_siginfo;
+
+  int size_termios;
+  int size_termios2;
+  int size_pid_t;
+  int size_winsize;
+  int size_char;
+  int size_serial_struct;
+  int size_serial_icounter_struct;
+  int size_hayes_esp_config;
+
+  /* the values of the second argument of system call "sys_ioctl".  */
+  int ioctl_TCGETS;
+  int ioctl_TCSETS;
+  int ioctl_TCSETSW;
+  int ioctl_TCSETSF;
+  int ioctl_TCGETA;
+  int ioctl_TCSETA;
+  int ioctl_TCSETAW;
+  int ioctl_TCSETAF;
+  int ioctl_TCSBRK;
+  int ioctl_TCXONC;
+  int ioctl_TCFLSH;
+  int ioctl_TIOCEXCL;
+  int ioctl_TIOCNXCL;
+  int ioctl_TIOCSCTTY;
+  int ioctl_TIOCGPGRP;
+  int ioctl_TIOCSPGRP;
+  int ioctl_TIOCOUTQ;
+  int ioctl_TIOCSTI;
+  int ioctl_TIOCGWINSZ;
+  int ioctl_TIOCSWINSZ;
+  int ioctl_TIOCMGET;
+  int ioctl_TIOCMBIS;
+  int ioctl_TIOCMBIC;
+  int ioctl_TIOCMSET;
+  int ioctl_TIOCGSOFTCAR;
+  int ioctl_TIOCSSOFTCAR;
+  int ioctl_FIONREAD;
+  int ioctl_TIOCINQ;
+  int ioctl_TIOCLINUX;
+  int ioctl_TIOCCONS;
+  int ioctl_TIOCGSERIAL;
+  int ioctl_TIOCSSERIAL;
+  int ioctl_TIOCPKT;
+  int ioctl_FIONBIO;
+  int ioctl_TIOCNOTTY;
+  int ioctl_TIOCSETD;
+  int ioctl_TIOCGETD;
+  int ioctl_TCSBRKP;
+  int ioctl_TIOCTTYGSTRUCT;
+  int ioctl_TIOCSBRK;
+  int ioctl_TIOCCBRK;
+  int ioctl_TIOCGSID;
+  int ioctl_TCGETS2;
+  int ioctl_TCSETS2;
+  int ioctl_TCSETSW2;
+  int ioctl_TCSETSF2;
+  int ioctl_TIOCGPTN;
+  int ioctl_TIOCSPTLCK;
+  int ioctl_FIONCLEX;
+  int ioctl_FIOCLEX;
+  int ioctl_FIOASYNC;
+  int ioctl_TIOCSERCONFIG;
+  int ioctl_TIOCSERGWILD;
+  int ioctl_TIOCSERSWILD;
+  int ioctl_TIOCGLCKTRMIOS;
+  int ioctl_TIOCSLCKTRMIOS;
+  int ioctl_TIOCSERGSTRUCT;
+  int ioctl_TIOCSERGETLSR;
+  int ioctl_TIOCSERGETMULTI;
+  int ioctl_TIOCSERSETMULTI;
+  int ioctl_TIOCMIWAIT;
+  int ioctl_TIOCGICOUNT;
+  int ioctl_TIOCGHAYESESP;
+  int ioctl_TIOCSHAYESESP;
+  int ioctl_FIOQSIZE;
+
+  /* The number of the registers that use to be the arguments of system call.  */
+  int arg1;
+  int arg2;
+  int arg3;
+  int arg4;
+  int arg5;
+} linux_record_tdep_t;
+
+extern int record_linux_system_call (int num, linux_record_tdep_t * tdep);
+
+#endif /* _LINUX_RECORD_H_ */
diff --git a/gdb/record.c b/gdb/record.c
new file mode 100644 (file)
index 0000000..8e2d13d
--- /dev/null
@@ -0,0 +1,1272 @@
+/* Process record and replay target for GDB, the GNU debugger.
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "target.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "record.h"
+
+#include <signal.h>
+
+#define DEFAULT_RECORD_INSN_MAX_NUM    200000
+
+int record_debug = 0;
+
+record_t record_first;
+record_t *record_list = &record_first;
+record_t *record_arch_list_head = NULL;
+record_t *record_arch_list_tail = NULL;
+struct regcache *record_regcache = NULL;
+
+/* 1 ask user. 0 auto delete the last record_t.  */
+static int record_stop_at_limit = 1;
+static int record_insn_max_num = DEFAULT_RECORD_INSN_MAX_NUM;
+static int record_insn_num = 0;
+
+struct target_ops record_ops;
+static int record_resume_step = 0;
+static enum target_signal record_resume_siggnal;
+static int record_get_sig = 0;
+static sigset_t record_maskall;
+static int record_not_record = 0;
+int record_will_store_registers = 0;
+
+extern struct bp_location *bp_location_chain;
+
+/* The real beneath function pointers.  */
+void (*record_beneath_to_resume) (ptid_t, int, enum target_signal);
+ptid_t (*record_beneath_to_wait) (ptid_t, struct target_waitstatus *);
+void (*record_beneath_to_store_registers) (struct regcache *, int regno);
+LONGEST (*record_beneath_to_xfer_partial) (struct target_ops * ops,
+                                          enum target_object object,
+                                          const char *annex,
+                                          gdb_byte * readbuf,
+                                          const gdb_byte * writebuf,
+                                          ULONGEST offset, LONGEST len);
+int (*record_beneath_to_insert_breakpoint) (struct bp_target_info *);
+int (*record_beneath_to_remove_breakpoint) (struct bp_target_info *);
+
+static void
+record_list_release (record_t * rec)
+{
+  record_t *tmp;
+
+  if (!rec)
+    return;
+
+  while (rec->next)
+    {
+      rec = rec->next;
+    }
+
+  while (rec->prev)
+    {
+      tmp = rec;
+      rec = rec->prev;
+      if (tmp->type == record_reg)
+       {
+         xfree (tmp->u.reg.val);
+       }
+      else if (tmp->type == record_mem)
+       {
+         xfree (tmp->u.mem.val);
+       }
+      xfree (tmp);
+    }
+
+  if (rec != &record_first)
+    {
+      xfree (rec);
+    }
+}
+
+static void
+record_list_release_next (void)
+{
+  record_t *rec = record_list;
+  record_t *tmp = rec->next;
+  rec->next = NULL;
+  while (tmp)
+    {
+      rec = tmp->next;
+      if (tmp->type == record_reg)
+       {
+         record_insn_num--;
+       }
+      else 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;
+    }
+}
+
+static void
+record_list_release_first (void)
+{
+  record_t *tmp = NULL;
+  enum record_type type;
+
+  if (!record_first.next)
+    {
+      return;
+    }
+
+  while (1)
+    {
+      type = record_first.next->type;
+
+      if (type == record_reg)
+       {
+         xfree (record_first.next->u.reg.val);
+       }
+      else if (type == record_mem)
+       {
+         xfree (record_first.next->u.mem.val);
+       }
+      tmp = record_first.next;
+      record_first.next = tmp->next;
+      xfree (tmp);
+
+      if (!record_first.next)
+       {
+         gdb_assert (record_insn_num == 1);
+         break;
+       }
+
+      record_first.next->prev = &record_first;
+
+      if (type == record_end)
+       {
+         break;
+       }
+    }
+
+  record_insn_num--;
+}
+
+/* Add a record_t to record_arch_list.  */
+static void
+record_arch_list_add (record_t * rec)
+{
+  if (record_arch_list_tail)
+    {
+      record_arch_list_tail->next = rec;
+      rec->prev = record_arch_list_tail;
+      record_arch_list_tail = rec;
+    }
+  else
+    {
+      record_arch_list_head = rec;
+      record_arch_list_tail = rec;
+    }
+}
+
+/* Record the value of a register ("num") to record_arch_list.  */
+int
+record_arch_list_add_reg (int num)
+{
+  record_t *rec;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "Process record: add register num = %d to record list.\n",
+                         num);
+    }
+
+  rec = (record_t *) xmalloc (sizeof (record_t));
+  rec->u.reg.val = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE);
+  rec->prev = NULL;
+  rec->next = NULL;
+  rec->type = record_reg;
+  rec->u.reg.num = num;
+
+  regcache_raw_read (record_regcache, num, rec->u.reg.val);
+
+  record_arch_list_add (rec);
+
+  return (0);
+}
+
+/* Record the value of a region of memory whose address is "addr" and
+   length is "len" to record_arch_list.  */
+
+int
+record_arch_list_add_mem (CORE_ADDR addr, int len)
+{
+  record_t *rec;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "Process record: add mem addr = 0x%s len = %d to record list.\n",
+                         paddr_nz (addr), len);
+    }
+
+  if (!addr)
+    {
+      return (0);
+    }
+
+  rec = (record_t *) xmalloc (sizeof (record_t));
+  rec->u.mem.val = (gdb_byte *) xmalloc (len);
+  rec->prev = NULL;
+  rec->next = NULL;
+  rec->type = record_mem;
+  rec->u.mem.addr = addr;
+  rec->u.mem.len = len;
+
+  if (target_read_memory (addr, rec->u.mem.val, len))
+    {
+      if (record_debug)
+       {
+         fprintf_unfiltered (gdb_stdlog,
+                             "Process record: error reading memory at addr = 0x%s len = %d.\n",
+                             paddr_nz (addr), len);
+       }
+      xfree (rec->u.mem.val);
+      xfree (rec);
+      return (-1);
+    }
+
+  record_arch_list_add (rec);
+
+  return (0);
+}
+
+/* Add a record_end type record_t to record_arch_list.  */
+int
+record_arch_list_add_end (int need_dasm)
+{
+  record_t *rec;
+
+  if (record_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "Process 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);
+}
+
+static void
+record_check_insn_num (int set_terminal)
+{
+  if (record_insn_max_num)
+    {
+      gdb_assert (record_insn_num <= record_insn_max_num);
+      if (record_insn_num == record_insn_max_num)
+       {
+         /* Ask user what to do */
+         if (record_stop_at_limit)
+           {
+             int q;
+             if (set_terminal)
+               target_terminal_ours ();
+             q = yquery (_("Do you want to auto delete previous execute log entries when record/replay buffer becomes full (record-stop-at-limit)?"));
+             if (set_terminal)
+               target_terminal_inferior ();
+             if (q)
+               {
+                 record_stop_at_limit = 0;
+               }
+             else
+               {
+                 error (_("Process record: inferior program stopped."));
+               }
+           }
+       }
+    }
+}
+
+/* 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_process_record to
+   record the running message of inferior and set them to
+   record_arch_list, and add it to record_list.  */
+
+static void
+record_message_cleanups (void *ignore)
+{
+  record_list_release (record_arch_list_tail);
+  set_executing (inferior_ptid, 0);
+  normal_stop ();
+}
+
+void
+record_message (struct gdbarch *gdbarch)
+{
+  int ret;
+  struct cleanup *old_cleanups = make_cleanup (record_message_cleanups, 0);
+
+  /* Check record_insn_num.  */
+  record_check_insn_num (1);
+
+  record_arch_list_head = NULL;
+  record_arch_list_tail = NULL;
+  record_regcache = get_current_regcache ();
+
+  ret = gdbarch_process_record (gdbarch,
+                               regcache_read_pc (record_regcache));
+  if (ret > 0)
+    error (_("Process record: inferior program stopped."));
+  if (ret < 0)
+    error (_("Process record: failed to record execution log."));
+
+  discard_cleanups (old_cleanups);
+
+  record_list->next = record_arch_list_head;
+  record_arch_list_head->prev = record_list;
+  record_list = record_arch_list_tail;
+
+  if (record_insn_num == record_insn_max_num && record_insn_max_num)
+    {
+      record_list_release_first ();
+    }
+  else
+    {
+      record_insn_num++;
+    }
+}
+
+/* Things to clean up if we QUIT out of function that set
+   record_not_record.  */
+static void
+record_not_record_cleanups (void *ignore)
+{
+  record_not_record = 0;
+}
+
+void
+record_not_record_set (void)
+{
+  struct cleanup *old_cleanups = make_cleanup (record_not_record_cleanups, 0);
+  record_not_record = 1;
+}
+
+static void
+record_open (char *name, int from_tty)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n");
+    }
+
+  /* check exec */
+  if (!target_has_execution)
+    {
+      error (_("Process record: the program is not being run."));
+    }
+  if (non_stop)
+    {
+      error (_("Process record target can't debug inferior in non-stop mode (non-stop)."));
+    }
+  if (target_async_permitted)
+    {
+      error (_("Process record target can't debug inferior in asynchronous mode (target-async)."));
+    }
+
+  if (!gdbarch_process_record_p (current_gdbarch))
+    {
+      error (_("Process record: the current architecture doesn't support record function."));
+    }
+
+  /* Check if record target is already running */
+  if (RECORD_IS_USED)
+    {
+      if (!nquery
+         (_("Process record target already running, do you want to delete the old record log?")))
+       {
+         return;
+       }
+    }
+
+  push_target (&record_ops);
+
+  /* Reset */
+  record_insn_num = 0;
+  record_list = &record_first;
+  record_list->next = NULL;
+}
+
+static void
+record_close (int quitting)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");
+    }
+  record_list_release (record_list);
+}
+
+static void
+record_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+  record_resume_step = step;
+  record_resume_siggnal = siggnal;
+
+  if (!RECORD_IS_REPLAY)
+    {
+      record_message (current_gdbarch);
+      record_beneath_to_resume (ptid, 1, siggnal);
+    }
+}
+
+static void
+record_sig_handler (int signo)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: get a signal\n");
+    }
+  record_resume_step = 1;
+  record_get_sig = 1;
+}
+
+static void
+record_wait_cleanups (void *ignore)
+{
+  if (execution_direction == EXEC_REVERSE)
+    {
+      if (record_list->next)
+       {
+         record_list = record_list->next;
+       }
+    }
+  else
+    {
+      record_list = record_list->prev;
+    }
+  set_executing (inferior_ptid, 0);
+  normal_stop ();
+}
+
+/* record_wait
+   In replay mode, this function examines the recorded log and
+   determines where to stop.  */
+
+static ptid_t
+record_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "Process record: record_wait record_resume_step = %d\n",
+                         record_resume_step);
+    }
+
+  if (!RECORD_IS_REPLAY)
+    {
+      if (record_resume_step)
+       {
+         /* This is a single step.  */
+         return record_beneath_to_wait (ptid, status);
+       }
+      else
+       {
+         if (record_resume_step)
+           {
+             /* This is a single step.  */
+             return record_beneath_to_wait (ptid, status);
+           }
+         else
+           {
+             /* This is not a single step.  */
+             ptid_t ret;
+             int is_breakpoint = 1;
+             CORE_ADDR pc;
+             int pc_is_read = 0;
+             struct bp_location *bl;
+             struct breakpoint *b;
+
+             do
+               {
+                 ret = record_beneath_to_wait (ptid, status);
+
+                 if (status->kind == TARGET_WAITKIND_STOPPED
+                     && status->value.sig == TARGET_SIGNAL_TRAP)
+                   {
+                     /* Check if there is a breakpoint.  */
+                     pc_is_read = 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_is_read)
+                           {
+                             pc =
+                               regcache_read_pc (get_thread_regcache (ret));
+                             pc_is_read = 1;
+                           }
+                         switch (b->type)
+                           {
+                           default:
+                             if (bl->address == pc)
+                               {
+                                 goto breakpoint;
+                               }
+                             break;
+
+                           case bp_watchpoint:
+                             /*XXX teawater: I still not very clear how to deal with it.  */
+                             goto breakpoint;
+                             break;
+
+                           case bp_catchpoint:
+                             gdb_assert (b->ops != NULL
+                                         && b->ops->breakpoint_hit != NULL);
+                             if (b->ops->breakpoint_hit (b))
+                               {
+                                 goto breakpoint;
+                               }
+                             break;
+
+                           case bp_hardware_watchpoint:
+                           case bp_read_watchpoint:
+                           case bp_access_watchpoint:
+                             if (STOPPED_BY_WATCHPOINT (0))
+                               {
+                                 goto breakpoint;
+                               }
+                             break;
+                           }
+                       }
+
+                     /* There is not a breakpoint.  */
+                     record_message (current_gdbarch);
+                     record_beneath_to_resume (ptid, 1,
+                                               record_resume_siggnal);
+                     continue;
+                   }
+
+                 is_breakpoint = 0;
+
+               breakpoint:
+                 /* Add gdbarch_decr_pc_after_break to pc because pc will
+                    be break at address add gdbarch_decr_pc_after_break
+                    when inferior non-step execute.  */
+                 if (is_breakpoint)
+                   {
+                     CORE_ADDR decr_pc_after_break =
+                       gdbarch_decr_pc_after_break (current_gdbarch);
+                     if (decr_pc_after_break)
+                       {
+                         if (!pc_is_read)
+                           {
+                             pc =
+                               regcache_read_pc (get_thread_regcache (ret));
+                           }
+                         regcache_write_pc (get_thread_regcache (ret),
+                                            pc + decr_pc_after_break);
+                       }
+                   }
+
+                 break;
+               }
+             while (1);
+
+             return ret;
+           }
+       }
+    }
+  else
+    {
+      struct sigaction act, old_act;
+      int need_dasm = 0;
+      struct regcache *regcache = get_current_regcache ();
+      int continue_flag = 1;
+      int first_record_end = 1;
+      struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0);
+      CORE_ADDR tmp_pc;
+
+      status->kind = TARGET_WAITKIND_STOPPED;
+
+      /* Check breakpoint when forward execute.  */
+      if (execution_direction == EXEC_FORWARD)
+       {
+         tmp_pc = regcache_read_pc (regcache);
+         if (breakpoint_inserted_here_p (tmp_pc))
+           {
+             if (record_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "Process record: break at 0x%s.\n",
+                                     paddr_nz (tmp_pc));
+               }
+             if (gdbarch_decr_pc_after_break (get_regcache_arch (regcache))
+                 && !record_resume_step)
+               {
+                 regcache_write_pc (regcache,
+                                    tmp_pc +
+                                    gdbarch_decr_pc_after_break
+                                    (get_regcache_arch (regcache)));
+               }
+             goto replay_out;
+           }
+       }
+
+      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 (_("Process record: sigaction failed"));
+       }
+      /* If GDB is in terminal_inferior, it will not get the signal.
+         And in GDB replay mode, GDB doesn't need to in terminal_inferior
+         because inferior will not executed.
+         Then set it to terminal_ours to make GDB get the signal.  */
+      target_terminal_ours ();
+
+      /* In EXEC_FORWARD mode, record_list point to the tail of prev
+         instruction.  */
+      if (execution_direction == EXEC_FORWARD && record_list->next)
+        {
+         record_list = record_list->next;
+       }
+
+      /* Loop over the record_list, looking for the next place to
+        stop.  */
+      do
+       {
+         /* Check for beginning and end of log.  */
+         if (execution_direction == EXEC_REVERSE
+             && record_list == &record_first)
+           {
+             /* Hit beginning of record log in reverse.  */
+             status->kind = TARGET_WAITKIND_NO_HISTORY;
+             break;
+           }
+         if (execution_direction != EXEC_REVERSE && !record_list->next)
+           {
+             /* Hit end of record log going forward.  */
+             status->kind = TARGET_WAITKIND_NO_HISTORY;
+             break;
+           }
+
+         /* set ptid, register and memory according to record_list */
+         if (record_list->type == record_reg)
+           {
+             /* reg */
+             gdb_byte reg[MAX_REGISTER_SIZE];
+             if (record_debug > 1)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "Process record: record_reg 0x%s to inferior num = %d.\n",
+                                     paddr_nz ((CORE_ADDR)record_list),
+                                     record_list->u.reg.num);
+               }
+             regcache_cooked_read (regcache, record_list->u.reg.num, reg);
+             regcache_cooked_write (regcache, record_list->u.reg.num,
+                                    record_list->u.reg.val);
+             memcpy (record_list->u.reg.val, reg, MAX_REGISTER_SIZE);
+           }
+         else if (record_list->type == record_mem)
+           {
+             /* mem */
+             gdb_byte *mem = alloca (record_list->u.mem.len);
+             if (record_debug > 1)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "Process record: record_mem 0x%s to inferior addr = 0x%s len = %d.\n",
+                                     paddr_nz ((CORE_ADDR)record_list),
+                                     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 (_("Process record: error reading memory at addr = 0x%s len = %d."),
+                        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 (_
+                        ("Process record: error writing memory at addr = 0x%s len = %d."),
+                        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 (record_debug > 1)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "Process record: record_end 0x%s to inferior need_dasm = %d.\n",
+                                     paddr_nz ((CORE_ADDR)record_list),
+                                     record_list->u.need_dasm);
+               }
+
+             if (execution_direction == EXEC_FORWARD)
+               {
+                 need_dasm = record_list->u.need_dasm;
+               }
+             if (need_dasm)
+               {
+                 gdbarch_process_record_dasm (current_gdbarch);
+               }
+
+             if (first_record_end && execution_direction == EXEC_REVERSE)
+               {
+                 /* When reverse excute, the first record_end is the part of
+                    current instruction.  */
+                 first_record_end = 0;
+               }
+             else
+               {
+                 /* In EXEC_REVERSE mode, this is the record_end of prev
+                    instruction.
+                    In EXEC_FORWARD mode, this is the record_end of current
+                    instruction.  */
+                 /* step */
+                 if (record_resume_step)
+                   {
+                     if (record_debug > 1)
+                       {
+                         fprintf_unfiltered (gdb_stdlog, "Process record: step.\n");
+                       }
+                     continue_flag = 0;
+                   }
+
+                 /* check breakpoint */
+                 tmp_pc = regcache_read_pc (regcache);
+                 if (breakpoint_inserted_here_p (tmp_pc))
+                   {
+                     if (record_debug)
+                       {
+                         fprintf_unfiltered (gdb_stdlog,
+                                             "Process record: break at 0x%s.\n",
+                                             paddr_nz (tmp_pc));
+                       }
+                     if (gdbarch_decr_pc_after_break (get_regcache_arch (regcache))
+                         && execution_direction == EXEC_FORWARD
+                         && !record_resume_step)
+                       {
+                         regcache_write_pc (regcache,
+                                            tmp_pc +
+                                            gdbarch_decr_pc_after_break
+                                            (get_regcache_arch (regcache)));
+                       }
+                     continue_flag = 0;
+                   }
+               }
+             if (execution_direction == EXEC_REVERSE)
+               {
+                 need_dasm = record_list->u.need_dasm;
+               }
+           }
+
+next:
+         if (continue_flag)
+           {
+             if (execution_direction == EXEC_REVERSE)
+               {
+                 if (record_list->prev)
+                   record_list = record_list->prev;
+               }
+             else
+               {
+                 if (record_list->next)
+                   record_list = record_list->next;
+               }
+           }
+       }
+      while (continue_flag);
+
+      if (sigaction (SIGALRM, &old_act, NULL))
+       {
+         perror_with_name (_("Process record: sigaction failed"));
+       }
+
+replay_out:
+      if (record_get_sig)
+       {
+         status->value.sig = TARGET_SIGNAL_INT;
+       }
+      else
+       {
+         status->value.sig = TARGET_SIGNAL_TRAP;
+       }
+
+      discard_cleanups (old_cleanups);
+    }
+
+  return inferior_ptid;
+}
+
+static void
+record_disconnect (struct target_ops *target, char *args, int from_tty)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: record_disconnect\n");
+    }
+  unpush_target (&record_ops);
+  target_disconnect (args, from_tty);
+}
+
+static void
+record_detach (struct target_ops *ops, char *args, int from_tty)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: record_detach\n");
+    }
+  unpush_target (&record_ops);
+  target_detach (args, from_tty);
+}
+
+static void
+record_mourn_inferior (struct target_ops *ops)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: record_mourn_inferior\n");
+    }
+  unpush_target (&record_ops);
+  target_mourn_inferior ();
+}
+
+/* Close process record target before kill the inferior process.  */
+static void
+record_kill (void)
+{
+  if (record_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n");
+    }
+  unpush_target (&record_ops);
+  target_kill ();
+}
+
+/* Record registers change (by user or by GDB) to list as an instruction.  */
+static void
+record_registers_change (struct regcache *regcache, int regnum)
+{
+  /* Check record_insn_num.  */
+  record_check_insn_num (0);
+
+  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 (_("Process record: failed to record execution log."));
+           }
+       }
+    }
+  else
+    {
+      if (record_arch_list_add_reg (regnum))
+       {
+         record_list_release (record_arch_list_tail);
+         error (_("Process record: failed to record execution log."));
+       }
+    }
+  if (record_arch_list_add_end (0))
+    {
+      record_list_release (record_arch_list_tail);
+      error (_("Process record: failed to record execution log."));
+    }
+  record_list->next = record_arch_list_head;
+  record_arch_list_head->prev = record_list;
+  record_list = record_arch_list_tail;
+
+  if (record_insn_num == record_insn_max_num && record_insn_max_num)
+    {
+      record_list_release_first ();
+    }
+  else
+    {
+      record_insn_num++;
+    }
+}
+
+static void
+record_store_registers (struct regcache *regcache, int regno)
+{
+  if (!record_not_record)
+    {
+      if (RECORD_IS_REPLAY)
+       {
+         int n;
+         struct cleanup *old_cleanups;
+
+         /* Let user choice if he want to write register or not.  */
+         if (regno < 0)
+           {
+             n =
+               nquery (_
+                       ("Becuse GDB is in replay mode, changing the value of a register will make the execute log unusable from this point onward.  Change all register?"));
+           }
+         else
+           {
+             n =
+               nquery (_
+                       ("Becuse GDB is in replay mode, changing the value of a register will make the execute log unusable from this point onward.  Change register %s?"),
+                       gdbarch_register_name (get_regcache_arch (regcache),
+                                              regno));
+           }
+
+         if (!n)
+           {
+             /* Invalidate the value of regcache that set in function
+                "regcache_raw_write".  */
+             if (regno < 0)
+               {
+                 int i;
+                 for (i = 0;
+                      i < gdbarch_num_regs (get_regcache_arch (regcache));
+                      i++)
+                   {
+                     regcache_invalidate (regcache, i);
+                   }
+               }
+             else
+               {
+                 regcache_invalidate (regcache, regno);
+               }
+
+             error (_("Process record canceled the operation."));
+           }
+
+         /* Destroy the record from here forward.  */
+         record_list_release_next ();
+       }
+
+      record_registers_change (regcache, regno);
+    }
+  record_beneath_to_store_registers (regcache, regno);
+}
+
+/* record_xfer_partial -- behavior is conditional on RECORD_IS_REPLAY.
+   In replay mode, we cannot write memory unles we are willing to
+   invalidate the record/replay log from this point forward.  */
+
+static LONGEST
+record_xfer_partial (struct target_ops *ops, enum target_object object,
+                    const char *annex, gdb_byte * readbuf,
+                    const gdb_byte * writebuf, ULONGEST offset, LONGEST len)
+{
+  if (!record_not_record
+      && (object == TARGET_OBJECT_MEMORY
+         || object == TARGET_OBJECT_RAW_MEMORY) && writebuf)
+    {
+      if (RECORD_IS_REPLAY)
+       {
+         /* Let user choice if he want to write memory or not.  */
+         if (!nquery (_("Because GDB is in replay mode, writing to memory will make the execute log unusable from this point onward.  Write memory at address 0x%s?"),
+                      paddr_nz (offset)))
+           {
+             return -1;
+           }
+
+         /* Destroy the record from here forward.  */
+         record_list_release_next ();
+       }
+
+      /* Check record_insn_num */
+      record_check_insn_num (0);
+
+      /* Record registers change to list as an instruction.  */
+      record_arch_list_head = NULL;
+      record_arch_list_tail = NULL;
+      if (record_arch_list_add_mem (offset, len))
+       {
+         record_list_release (record_arch_list_tail);
+         if (record_debug)
+           {
+             fprintf_unfiltered (gdb_stdlog,
+                                 _
+                                 ("Process record: failed to record execution log."));
+           }
+         return -1;
+       }
+      if (record_arch_list_add_end (0))
+       {
+         record_list_release (record_arch_list_tail);
+         if (record_debug)
+           {
+             fprintf_unfiltered (gdb_stdlog,
+                                 _
+                                 ("Process record: failed to record execution log."));
+           }
+         return -1;
+       }
+      record_list->next = record_arch_list_head;
+      record_arch_list_head->prev = record_list;
+      record_list = record_arch_list_tail;
+
+      if (record_insn_num == record_insn_max_num && record_insn_max_num)
+       {
+         record_list_release_first ();
+       }
+      else
+       {
+         record_insn_num++;
+       }
+    }
+
+  return record_beneath_to_xfer_partial (ops, object, annex, readbuf,
+                                        writebuf, offset, len);
+}
+
+/* record_insert_breakpoint
+   record_remove_breakpoint
+   Behavior is conditional on RECORD_IS_REPLAY.
+   We will not actually insert or remove breakpoints when replaying.  */
+
+static int
+record_insert_breakpoint (struct bp_target_info *bp_tgt)
+{
+  if (!RECORD_IS_REPLAY)
+    {
+      return record_beneath_to_insert_breakpoint (bp_tgt);
+    }
+
+  return 0;
+}
+
+static int
+record_remove_breakpoint (struct bp_target_info *bp_tgt)
+{
+  if (!RECORD_IS_REPLAY)
+    {
+      return record_beneath_to_remove_breakpoint (bp_tgt);
+    }
+
+  return 0;
+}
+
+static int
+record_can_execute_reverse (void)
+{
+  return 1;
+}
+
+static void
+init_record_ops (void)
+{
+  record_ops.to_shortname = "record";
+  record_ops.to_longname = "Process record and replay target";
+  record_ops.to_doc =
+    "Log program while executing and replay execution from log.";
+  record_ops.to_open = record_open;
+  record_ops.to_close = record_close;
+  record_ops.to_resume = record_resume;
+  record_ops.to_wait = record_wait;
+  record_ops.to_disconnect = record_disconnect;
+  record_ops.to_detach = record_detach;
+  record_ops.to_mourn_inferior = record_mourn_inferior;
+  record_ops.to_kill = record_kill;
+  record_ops.to_create_inferior = find_default_create_inferior;        /* Make record suppport command "run".  */
+  record_ops.to_store_registers = record_store_registers;
+  record_ops.to_xfer_partial = record_xfer_partial;
+  record_ops.to_insert_breakpoint = record_insert_breakpoint;
+  record_ops.to_remove_breakpoint = record_remove_breakpoint;
+  record_ops.to_can_execute_reverse = record_can_execute_reverse;
+  record_ops.to_stratum = record_stratum;
+  record_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+show_record_debug (struct ui_file *file, int from_tty,
+                  struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Debugging of process record target is %s.\n"), value);
+}
+
+/* cmd_record_start -- alias for "target record".  */
+
+static void
+cmd_record_start (char *args, int from_tty)
+{
+  execute_command ("target record", from_tty);
+}
+
+/* cmd_record_delete -- truncate the record log from the present point
+   of replay until the end.  */
+
+static void
+cmd_record_delete (char *args, int from_tty)
+{
+  if (RECORD_IS_USED)
+    {
+      if (RECORD_IS_REPLAY)
+       {
+         if (!from_tty || query (_("Delete the log from this point forward and begin to record the running message at current PC?")))
+           {
+             record_list_release_next ();
+           }
+       }
+      else
+       {
+         printf_unfiltered (_("Already at end of record list.\n"));
+       }
+
+    }
+  else
+    {
+      printf_unfiltered (_("Process record is not started.\n"));
+    }
+}
+
+/* cmd_record_stop -- implement the "stoprecord" command.  */
+
+static void
+cmd_record_stop (char *args, int from_tty)
+{
+  if (RECORD_IS_USED)
+    {
+      if (!record_list || !from_tty || query (_("Delete recorded log and stop recording?")))
+       {
+         unpush_target (&record_ops);
+       }
+    }
+  else
+    {
+      printf_unfiltered (_("Process record is not started.\n"));
+    }
+}
+
+/* set_record_insn_max_num -- set upper limit of record log size.  */
+
+static void
+set_record_insn_max_num (char *args, int from_tty, struct cmd_list_element *c)
+{
+  if (record_insn_num > record_insn_max_num && record_insn_max_num)
+    {
+      printf_unfiltered (_("Record instructions number is bigger than record instructions max number.  Auto delete the first ones?\n"));
+
+      while (record_insn_num > record_insn_max_num)
+       {
+         record_list_release_first ();
+       }
+    }
+}
+
+/* show_record_insn_number -- print the current index
+   into the record log (number of insns recorded so far).  */
+
+static void
+show_record_insn_number (char *ignore, int from_tty)
+{
+  printf_unfiltered (_("Record instruction number is %d.\n"),
+                    record_insn_num);
+}
+
+void
+_initialize_record (void)
+{
+  /* Init record_maskall.  */
+  if (sigfillset (&record_maskall) == -1)
+    {
+      perror_with_name (_("Process record: sigfillset failed"));
+    }
+
+  /* Init record_first.  */
+  record_first.prev = NULL;
+  record_first.next = NULL;
+  record_first.type = record_end;
+  record_first.u.need_dasm = 0;
+
+  init_record_ops ();
+  add_target (&record_ops);
+
+  add_setshow_zinteger_cmd ("record", no_class, &record_debug,
+                           _("Set debugging of record/replay feature."),
+                           _("Show debugging of record/replay feature."),
+                           _
+                           ("When enabled, debugging output for record/replay feature is displayed."),
+                           NULL, show_record_debug, &setdebuglist,
+                           &showdebuglist);
+
+  add_com ("record", class_obscure, cmd_record_start,
+          _("Abbreviated form of \"target record\" command."));
+
+  add_com_alias ("rec", "record", class_obscure, 1);
+
+  /* XXX: I try to use some simple commands such as "disconnect" and
+     "detach" to support this functions.  But these commands all have
+     other affect to GDB such as call function "no_shared_libraries".
+     So I add special commands to GDB.  */
+  add_com ("delrecord", class_obscure, cmd_record_delete,
+          _("Delete the rest of execution log and start recording it anew."));
+  add_com_alias ("dr", "delrecord", class_obscure, 1);
+  add_com ("stoprecord", class_obscure, cmd_record_stop,
+          _("Stop the record/replay target."));
+  add_com_alias ("sr", "stoprecord", class_obscure, 1);
+
+  /* Record instructions number limit command.  */
+  add_setshow_boolean_cmd ("record-stop-at-limit", no_class,
+                           &record_stop_at_limit,
+                           _("Set whether record/replay stop when record/replay buffer becomes full."),
+                           _("Show whether record/replay stop when record/replay buffer becomes full."), _("\
+Enable is default value.\n\
+When enabled, if the record/replay buffer becomes full,\n\
+ask user what to do.\n\
+When disabled, if the record/replay buffer becomes full,\n\
+delete it and start new recording."), NULL, NULL, &setlist, &showlist);
+  add_setshow_zinteger_cmd ("record-insn-number-max", no_class,
+                           &record_insn_max_num,
+                           _("Set record/replay buffer limit."),
+                           _("Show record/replay buffer limit."), _("\
+Set the maximum number of instructions to be stored in the\n\
+record/replay buffer.  Zero means unlimited (default 200000)."),
+                           set_record_insn_max_num,
+                           NULL, &setlist, &showlist);
+  add_info ("record-insn-number", show_record_insn_number, _("\
+Show the current number of instructions in the record/replay buffer."));
+}
diff --git a/gdb/record.h b/gdb/record.h
new file mode 100644 (file)
index 0000000..fd69273
--- /dev/null
@@ -0,0 +1,98 @@
+/* Process record and replay target for GDB, the GNU debugger.
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _RECORD_H_
+#define _RECORD_H_
+
+#define RECORD_IS_USED   \
+     (current_target.beneath == &record_ops)
+#define RECORD_IS_REPLAY \
+     (record_list->next || execution_direction == EXEC_REVERSE)
+
+typedef struct record_reg_s
+{
+  int num;
+  gdb_byte *val;
+} record_reg_t;
+
+typedef struct record_mem_s
+{
+  CORE_ADDR addr;
+  int len;
+  gdb_byte *val;
+} record_mem_t;
+
+enum record_type
+{
+  record_end = 0,
+  record_reg,
+  record_mem
+};
+
+/* This is the core struct of record function.
+   An entity of record_t is a record of the value change of a register
+   ("record_reg") or a part of memory ("record_mem"). And Each instruction must
+   has a record_t ("record_end") that point out this is the last record_t of
+   this instruction.
+   Each record_t is linked to "record_list" by "prev" and "next".
+ */
+typedef struct record_s
+{
+  struct record_s *prev;
+  struct record_s *next;
+  enum record_type type;
+  union
+  {
+    /* reg */
+    record_reg_t reg;
+    /* mem */
+    record_mem_t mem;
+    /* end */
+    int need_dasm;
+  } u;
+} record_t;
+
+extern int record_debug;
+extern record_t *record_list;
+extern record_t *record_arch_list_head;
+extern record_t *record_arch_list_tail;
+extern struct regcache *record_regcache;
+
+extern struct target_ops record_ops;
+
+extern int record_arch_list_add_reg (int num);
+extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
+extern int record_arch_list_add_end (int need_dasm);
+extern void record_message (struct gdbarch *gdbarch);
+extern void record_not_record_set (void);
+
+extern void (*record_beneath_to_resume) (ptid_t, int, enum target_signal);
+extern ptid_t (*record_beneath_to_wait) (ptid_t, struct target_waitstatus *);
+extern void (*record_beneath_to_store_registers) (struct regcache *, int regno);
+extern LONGEST (*record_beneath_to_xfer_partial) (struct target_ops * ops,
+                                                 enum target_object object,
+                                                 const char *annex,
+                                                 gdb_byte * readbuf,
+                                                 const gdb_byte * writebuf,
+                                                 ULONGEST offset,
+                                                 LONGEST len);
+extern int (*record_beneath_to_insert_breakpoint) (struct bp_target_info *);
+extern int (*record_beneath_to_remove_breakpoint) (struct bp_target_info *);
+
+#endif /* _RECORD_H_ */
index c16b55cd292b7588dc7700534b6310e804e39788..a6365985dbb5c967a809eb8898c2be1e9f03206a 100644 (file)
@@ -41,6 +41,7 @@
 #include "target-descriptions.h"
 #include "gdbthread.h"
 #include "solib.h"
+#include "record.h"
 
 static void target_info (char *, int);
 
@@ -405,6 +406,12 @@ update_current_target (void)
       if (!current_target.FIELD) \
        current_target.FIELD = (TARGET)->FIELD
 
+  record_beneath_to_resume = NULL;
+  record_beneath_to_store_registers = NULL;
+  record_beneath_to_xfer_partial = NULL;
+  record_beneath_to_insert_breakpoint = NULL;
+  record_beneath_to_remove_breakpoint = NULL;
+
   for (t = target_stack; t; t = t->beneath)
     {
       INHERIT (to_shortname, t);
@@ -494,6 +501,35 @@ update_current_target (void)
       /* Do not inherit to_memory_map.  */
       /* Do not inherit to_flash_erase.  */
       /* Do not inherit to_flash_done.  */
+
+      /* Set pointers to functions in the target beneath us.  */
+      if (t != &record_ops)
+        {
+           if (!record_beneath_to_resume)
+             {
+               record_beneath_to_resume = t->to_resume;
+             }
+           if (!record_beneath_to_wait)
+             {
+               record_beneath_to_wait = t->to_wait;
+             }
+           if (!record_beneath_to_store_registers)
+             {
+               record_beneath_to_store_registers = t->to_store_registers;
+             }
+           if (!record_beneath_to_xfer_partial)
+             {
+               record_beneath_to_xfer_partial = t->to_xfer_partial;
+             }
+           if (!record_beneath_to_insert_breakpoint)
+             {
+               record_beneath_to_insert_breakpoint = t->to_insert_breakpoint;
+             }
+           if (!record_beneath_to_remove_breakpoint)
+             {
+               record_beneath_to_remove_breakpoint = t->to_remove_breakpoint;
+             }
+        }
     }
 #undef INHERIT
 
index 2722945edb4aa66317e2ce5d10f5cc07146ea129..7244f943f08237b1cd5360e8702945447e32a199 100644 (file)
@@ -62,7 +62,8 @@ enum strata
     file_stratum,              /* Executable files, etc */
     core_stratum,              /* Core dump files */
     process_stratum,           /* Executing processes */
-    thread_stratum             /* Executing threads */
+    thread_stratum,            /* Executing threads */
+    record_stratum             /* Support record debugging */
   };
 
 enum thread_control_capabilities
index ef35b13865731449ad74d8bd285f4ed41125ee17..1f39ba91092ec11575c5fffbeb447432098d1f58 100755 (executable)
@@ -3131,7 +3131,7 @@ done
 
 
 
-                                                                                                                                                                                                        ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+                                                                                                                                                                                                        ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.twreverse/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -3699,6 +3699,7 @@ do
   "gdb.opt/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.opt/Makefile" ;;
   "gdb.pascal/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.pascal/Makefile" ;;
   "gdb.python/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.python/Makefile" ;;
+  "gdb.twreverse/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.twreverse/Makefile" ;;
   "gdb.threads/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.threads/Makefile" ;;
   "gdb.trace/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.trace/Makefile" ;;
   "gdb.xml/Makefile" ) CONFIG_FILES="$CONFIG_FILES gdb.xml/Makefile" ;;
index 3d8fae4a616897ac6157eccbba4ce55e46571511..4446115210bcaa8ce5a26091fe3ecd6282951507 100644 (file)
@@ -117,5 +117,5 @@ AC_OUTPUT([Makefile \
   gdb.fortran/Makefile gdb.server/Makefile \
   gdb.java/Makefile gdb.mi/Makefile gdb.modula2/Makefile \
   gdb.objc/Makefile gdb.opt/Makefile gdb.pascal/Makefile \
-  gdb.python/Makefile \
+  gdb.python/Makefile gdb.twreverse/Makefile \
   gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile])
index 3b4b0f63d3deca92adb1d9e54ff25b2fdd749049..f27674a5ee8e76ab1fb2b3a5308bf64b9fb1e14d 100644 (file)
@@ -35,6 +35,7 @@
 #   shared library variable
 #   heap variable (pointer)...
 #   overlay variables...
+#   Test forward replay
 #
 
 
@@ -71,7 +72,7 @@ gdb_continue_to_breakpoint "end of main" ".*/$srcfile:$endmain.*"
 # Now run backward to each of several points where data is changed.
 #
 
-# Module global variable
+# Module global variable, reverse
 
 set breakloc [gdb_get_line_number \
                  "module_global_state: set breakpoint here" $srcfile]
@@ -81,12 +82,12 @@ gdb_test "reverse-continue" ".*/$srcfile:$breakloc.*" "reverse to $breakloc"
 
 gdb_test "print aglobal" ".* = 0$newline"  "module global reverse-breakpoint"
 gdb_test "step"          ".* module global post-change .*" ""
-gdb_test "print aglobal" ".* = 1$newline"  "module global forward"
+gdb_test "print aglobal" ".* = 1$newline"  "module global forward past bp"
 gdb_test "reverse-step"  ".*$newline$breakloc.*" ""
-gdb_test "print aglobal" ".* = 0$newline"  "module global reverse-step"
+gdb_test "print aglobal" ".* = 0$newline"  "module global reverse-step to bp"
 
 
-# Module static variable
+# Module static variable, reverse
 
 set breakloc [gdb_get_line_number \
                  "module_static_state: set breakpoint here" $srcfile]
@@ -100,7 +101,7 @@ gdb_test "print astatic" ".* = 1$newline"  "module static forward"
 gdb_test "reverse-step"  ".*$newline$breakloc.*" ""
 gdb_test "print astatic" ".* = 0$newline"  "module static reverse-step"
 
-# Function static variable
+# Function static variable, reverse
 
 set breakloc [gdb_get_line_number \
                  "function_static_state: set breakpoint here" $srcfile]
@@ -114,7 +115,7 @@ gdb_test "print a"      ".* = 1$newline"  "function static forward"
 gdb_test "reverse-step" ".*$newline$breakloc.*" ""
 gdb_test "print a"      ".* = 0$newline"  "function static reverse-step"
 
-# Auto variable
+# Auto variable, reverse
 
 set breakloc [gdb_get_line_number \
                  "auto_state: set breakpoint here" $srcfile]
@@ -128,7 +129,7 @@ gdb_test "print a"      ".* = 1$newline"  "auto var forward"
 gdb_test "reverse-step" ".*$newline$breakloc.*" ""
 gdb_test "print a"      ".* = 0$newline"  "auto var reverse-step"
 
-# Register variable
+# Register variable, reverse
 
 set breakloc [gdb_get_line_number \
                  "register_state: set breakpoint here" $srcfile]
@@ -138,7 +139,89 @@ gdb_test "reverse-continue" ".*/$srcfile:$breakloc.*" "reverse to $breakloc"
 
 gdb_test "print a"      ".* = 0$newline"  "register var reverse-breakpoint"
 gdb_test "step"         ".* register post-change .*" ""
-gdb_test "print a"      ".* = 1$newline"  "register var forward"
+gdb_test "print a"      ".* = 1$newline"  "register var step post-change"
 gdb_test "reverse-step" ".*$newline$breakloc.*" ""
-gdb_test "print a"      ".* = 0$newline"  "register var reverse-step"
+gdb_test "print a"      ".* = 0$newline"  "register var reverse step-to"
+
+# Proceed to beginning of main
+
+gdb_test "tbreak $beginmain" ".*/$srcfile, line $beginmain.*" ""
+gdb_test "reverse-continue"  ".*/$srcfile:$beginmain.*" "reverse to main"
+
+# Now repeat tests while replaying forward.
+
+# Register variable, forward
+
+set breakloc [gdb_get_line_number \
+                 "register_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "register var forward-breakpoint"
+gdb_test "reverse-step" ".*hide.*" ""
+gdb_test "step"         ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "register var forward step-to"
+gdb_test "step"         ".* register post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "register var step post-change"
+
+# Auto variable, forward
+
+set breakloc [gdb_get_line_number \
+                 "auto_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "auto var forward-breakpoint"
+gdb_test "reverse-step" ".*hide.*" ""
+gdb_test "step"         ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "auto var forward step-to"
+gdb_test "step"         ".* auto post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "auto var step post-change"
+
+# Function static variable, forward
+
+set breakloc [gdb_get_line_number \
+                 "function_static_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print a"      ".* = 0$newline"  "function static forward-breakpoint"
+gdb_test "reverse-step" ".*hide.*" ""
+gdb_test "step"         ".*$newline$breakloc.*" ""
+gdb_test "print a"      ".* = 0$newline"  "function static forward step-to"
+gdb_test "step"         ".* function static post-change .*" ""
+gdb_test "print a"      ".* = 1$newline"  "function static step post-change"
+
+# Module static variable, forward
+
+set breakloc [gdb_get_line_number \
+                 "module_static_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print astatic" ".* = 0$newline"  "module static forward-breakpoint"
+gdb_test "reverse-step"  ".*hide.*" ""
+gdb_test "step"          ".*$newline$breakloc.*" ""
+gdb_test "print astatic" ".* = 0$newline"  "module static forward step-to"
+gdb_test "step"          ".* module static post-change .*" ""
+gdb_test "print astatic" ".* = 1$newline"  "module static step post-change"
+
+# Module global variable, forward
+
+set breakloc [gdb_get_line_number \
+                 "module_global_state: set breakpoint here" $srcfile]
+
+gdb_test "tbreak $breakloc" ".*/$srcfile, line $breakloc.*" ""
+gdb_test "continue"         ".*/$srcfile:$breakloc.*" "forward to $breakloc"
+
+gdb_test "print aglobal" ".* = 0$newline"  "module global forward-breakpoint"
+gdb_test "reverse-step"  ".*hide.*" ""
+gdb_test "step"          ".*$newline$breakloc.*" ""
+gdb_test "print aglobal" ".* = 0$newline"  "module global forward step-to"
+gdb_test "step"          ".* module global post-change .*" ""
+gdb_test "print aglobal" ".* = 1$newline"  "module global step post-change"