aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Snyder <msnyder@vmware.com>2008-12-26 21:09:13 +0000
committerMichael Snyder <msnyder@vmware.com>2008-12-26 21:09:13 +0000
commit188e9314e3536b0ab0b2d5a78baffc7b7dfccd56 (patch)
tree8395e9ef763ecf087387a5d188f4425c479f1ace
parent6f581415c153fc050f7c12ba17016825506a719e (diff)
downloadgdb-188e9314e3536b0ab0b2d5a78baffc7b7dfccd56.zip
gdb-188e9314e3536b0ab0b2d5a78baffc7b7dfccd56.tar.gz
gdb-188e9314e3536b0ab0b2d5a78baffc7b7dfccd56.tar.bz2
2008-12-26 Michael Snyder <msnyder@vmware.com>
* Marker: adding teawater patches to branch.
-rw-r--r--gdb/ChangeLog4
-rw-r--r--gdb/Makefile.in8
-rw-r--r--gdb/configure.tgt6
-rw-r--r--gdb/doc/gdb.texinfo107
-rw-r--r--gdb/gdbarch.c66
-rw-r--r--gdb/gdbarch.h14
-rwxr-xr-xgdb/gdbarch.sh4
-rw-r--r--gdb/i386-linux-tdep.c318
-rw-r--r--gdb/i386-tdep.c2964
-rw-r--r--gdb/i386-tdep.h3
-rw-r--r--gdb/infrun.c11
-rw-r--r--gdb/linux-record.c2507
-rw-r--r--gdb/linux-record.h171
-rw-r--r--gdb/record.c1272
-rw-r--r--gdb/record.h98
-rw-r--r--gdb/target.c36
-rw-r--r--gdb/target.h3
-rwxr-xr-xgdb/testsuite/configure3
-rw-r--r--gdb/testsuite/configure.ac2
-rw-r--r--gdb/testsuite/gdb.twreverse/machinestate.exp101
20 files changed, 7679 insertions, 19 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index c78678b..39ecb43 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 47b3be0..0935ffe 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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 \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index b9cd21b..d81cded 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -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)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6ef124c..c758952 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index dd6ad7f..de07768 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -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 */
@@ -922,6 +928,18 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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));
fprintf_unfiltered (file,
@@ -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)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 35f8a36..19b1b1f 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -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. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 79ca862..8a827f4 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -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
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index 5284f4a..6b8bf9b 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -37,6 +37,10 @@
#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;
+}
/* 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);
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index edaac21..fba6cee 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -49,6 +49,9 @@
#include "i386-tdep.h"
#include "i387-tdep.h"
+#include "record.h"
+#include <stdint.h>
+
/* Register names. */
static char *i386_register_names[] =
@@ -2638,6 +2641,2965 @@ i386_skip_permanent_breakpoint (struct regcache *regcache)
}
+#define PREFIX_REPZ 0x01
+#define PREFIX_REPNZ 0x02
+#define PREFIX_LOCK 0x04
+#define PREFIX_DATA 0x08
+#define PREFIX_ADDR 0x10
+
+/* operand size */
+enum
+{
+ OT_BYTE = 0,
+ OT_WORD,
+ OT_LONG,
+};
+
+/* i386 arith/logic operations */
+enum
+{
+ OP_ADDL,
+ OP_ORL,
+ OP_ADCL,
+ OP_SBBL,
+ OP_ANDL,
+ OP_SUBL,
+ OP_XORL,
+ OP_CMPL,
+};
+
+static int aflag = 1;
+static int dflag = 1;
+static int override = 0;
+static uint8_t modrm;
+static uint8_t mod, reg, rm;
+static int ot;
+static CORE_ADDR i386_record_pc;
+
+/* Parse "modrm" part in current memory address that i386_record_pc point to.
+ Return -1 if something wrong. */
+static int
+i386_record_modrm (void)
+{
+ if (target_read_memory (i386_record_pc, &modrm, 1))
+ {
+ 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;
+
+ return (0);
+}
+
+/* Get the memory address that current instruction write to and set it to
+ the argument "addr".
+ Return -1 if something wrong. */
+static int
+i386_record_lea_modrm_addr (uint32_t * addr)
+{
+ uint8_t tmpu8;
+ uint16_t tmpu16;
+ uint32_t tmpu32;
+
+ *addr = 0;
+ if (aflag)
+ {
+ /* 32 bits */
+ int havesib = 0;
+ uint8_t scale = 0;
+ uint8_t index = 0;
+ uint8_t base = rm;
+
+ if (base == 4)
+ {
+ havesib = 1;
+ if (target_read_memory (i386_record_pc, &tmpu8, 1))
+ {
+ 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);
+ }
+
+ 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;
+ }
+
+ if (base != 0xff)
+ {
+ regcache_raw_read (record_regcache, base, (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ }
+
+ /* XXX: index == 4 is always invalid */
+ if (havesib && (index != 4 || scale != 0))
+ {
+ regcache_raw_read (record_regcache, index, (gdb_byte *) & tmpu32);
+ *addr += tmpu32 << scale;
+ }
+ }
+ else
+ {
+ /* 16 bits */
+ switch (mod)
+ {
+ case 0:
+ if (rm == 6)
+ {
+ if (target_read_memory
+ (i386_record_pc, (gdb_byte *) & tmpu16, 2))
+ {
+ 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;
+ }
+
+ switch (rm)
+ {
+ case 0:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 1:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 2:
+ regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 3:
+ regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 4:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 5:
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 6:
+ regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 7:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ }
+ *addr &= 0xffff;
+ }
+
+no_rm:
+ return (0);
+}
+
+/* Record the value of the memory that willbe changed in current instruction
+ to "record_arch_list".
+ Return -1 if something wrong. */
+static int
+i386_record_lea_modrm (void)
+{
+ uint32_t addr;
+
+ if (override)
+ {
+ 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);
+ }
+
+ if (i386_record_lea_modrm_addr (&addr))
+ {
+ return (-1);
+ }
+
+ if (record_arch_list_add_mem (addr, 1 << ot))
+ {
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Parse the current instruction and record the values of the registers and
+ memory that will be changed in current instruction to "record_arch_list".
+ Return -1 if something wrong. */
+static int
+i386_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));
+ }
+
+ /* 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;
+ }
+
+ /* 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;
+
+ /* 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;
+ }
+
+ 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);
+}
+
static struct gdbarch *
i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
@@ -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;
}
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index d1366b6..a5ba588 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -106,6 +106,9 @@ struct gdbarch_tdep
/* ISA-specific data types. */
struct type *i386_mmx_type;
struct type *i386_sse_type;
+
+ int (*i386_intx80_record) (void);
+ int (*i386_sysenter_record) (void);
};
/* Floating-point registers. */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index eb2528c..95022a2 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -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
index 0000000..b5dae50
--- /dev/null
+++ b/gdb/linux-record.c
@@ -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
index 0000000..b0dd048
--- /dev/null
+++ b/gdb/linux-record.h
@@ -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
index 0000000..8e2d13d
--- /dev/null
+++ b/gdb/record.c
@@ -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
index 0000000..fd69273
--- /dev/null
+++ b/gdb/record.h
@@ -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_ */
diff --git a/gdb/target.c b/gdb/target.c
index c16b55c..a636598 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -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
diff --git a/gdb/target.h b/gdb/target.h
index 2722945..7244f94 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -62,7 +62,8 @@ enum strata
file_stratum, /* Executable files, etc */
core_stratum, /* Core dump files */
process_stratum, /* Executing processes */
- thread_stratum /* Executing threads */
+ thread_stratum, /* Executing threads */
+ record_stratum /* Support record debugging */
};
enum thread_control_capabilities
diff --git a/gdb/testsuite/configure b/gdb/testsuite/configure
index ef35b13..1f39ba9 100755
--- a/gdb/testsuite/configure
+++ b/gdb/testsuite/configure
@@ -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" ;;
diff --git a/gdb/testsuite/configure.ac b/gdb/testsuite/configure.ac
index 3d8fae4..4446115 100644
--- a/gdb/testsuite/configure.ac
+++ b/gdb/testsuite/configure.ac
@@ -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])
diff --git a/gdb/testsuite/gdb.twreverse/machinestate.exp b/gdb/testsuite/gdb.twreverse/machinestate.exp
index 3b4b0f6..f27674a 100644
--- a/gdb/testsuite/gdb.twreverse/machinestate.exp
+++ b/gdb/testsuite/gdb.twreverse/machinestate.exp
@@ -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"