* GDB record patch 0.1.3.1 for GDB-6.8 release
@ 2008-04-23 8:55 Tea
2008-05-20 4:33 ` Thiago Jung Bauermann
2008-05-23 3:52 ` Pedro Alves
0 siblings, 2 replies; 33+ messages in thread
From: Tea @ 2008-04-23 8:55 UTC (permalink / raw)
To: Michael Snyder, Thiago Jung Bauermann; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 274 bytes --]
Hi Michael and Thiago,
most part of GDB record patch 0.1.3.1 is same with GDB record patch
0.1.3 (http://sourceware.org/ml/gdb-patches/2008-04/msg00300.html). I
just did some change according to your mail. I must express the
particularly grateful to you.
Thanks,
teawater
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gdb-6.8-record-0.1.3.1.patch --]
[-- Type: text/x-patch; name=gdb-6.8-record-0.1.3.1.patch, Size: 167200 bytes --]
Patch to make make I386-Linux GDB support Reversible Debugging (http://sourceforge.net/projects/record/)
---
Makefile.in | 6
gdbarch.c | 46
gdbarch.h | 13
i386-linux-tdep.c | 2533 +++++++++++++++++++++++++++++++++++++++++++++++++
i386-tdep.c | 2769 +++++++++++++++++++++++++++++++++++++++++++++++++++---
i386-tdep.h | 3
infcmd.c | 47
inferior.h | 6
infrun.c | 130 ++
mips-tdep.c | 734 ++++++++++++++
record.c | 606 +++++++++++
record.h | 81 +
target.c | 15
target.h | 3
14 files changed, 6859 insertions(+), 133 deletions(-)
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -230,6 +230,8 @@ struct gdbarch
gdbarch_core_read_description_ftype *core_read_description;
gdbarch_static_transform_name_ftype *static_transform_name;
int sofun_address_maybe_missing;
+ gdbarch_record_ftype *record;
+ gdbarch_record_dasm_ftype *record_dasm;
};
@@ -352,6 +354,8 @@ struct gdbarch startup_gdbarch =
0, /* core_read_description */
0, /* static_transform_name */
0, /* sofun_address_maybe_missing */
+ NULL,
+ NULL,
/* startup_gdbarch() */
};
@@ -3391,6 +3395,48 @@ deprecated_current_gdbarch_select_hack (
reinit_frame_cache ();
}
+
+int
+gdbarch_record_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return (gdbarch->record != NULL);
+}
+
+int
+gdbarch_record (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->record != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_record called\n");
+ return (gdbarch->record (gdbarch));
+}
+
+void
+set_gdbarch_record (struct gdbarch *gdbarch, gdbarch_record_ftype * record)
+{
+ gdbarch->record = record;
+}
+
+void
+gdbarch_record_dasm (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->record_dasm != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_record_dasm called\n");
+ gdbarch->record_dasm (gdbarch);
+}
+
+void
+set_gdbarch_record_dasm (struct gdbarch *gdbarch,
+ gdbarch_record_dasm_ftype * record_dasm)
+{
+ gdbarch->record_dasm = record_dasm;
+}
+
+
extern void _initialize_gdbarch (void);
void
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -900,4 +900,17 @@ extern int gdbarch_debug;
extern void gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file);
+
+extern int gdbarch_record_p (struct gdbarch *gdbarch);
+typedef int (gdbarch_record_ftype) (struct gdbarch *gdbarch);
+extern int gdbarch_record (struct gdbarch *gdbarch);
+extern void set_gdbarch_record (struct gdbarch *gdbarch,
+ gdbarch_record_ftype * record);
+
+typedef void (gdbarch_record_dasm_ftype) (struct gdbarch *gdbarch);
+extern void gdbarch_record_dasm (struct gdbarch *gdbarch);
+extern void set_gdbarch_record_dasm (struct gdbarch *gdbarch,
+ gdbarch_record_dasm_ftype * record_dasm);
+
+
#endif
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -35,6 +35,9 @@
#include "solib-svr4.h"
#include "symtab.h"
+#include "record.h"
+#include <stdint.h>
+
/* Return the name of register REG. */
static const char *
@@ -335,6 +338,2533 @@ i386_linux_write_pc (struct regcache *re
restarted. */
regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1);
}
+
+
+/* These macros are the size of the type that will be use in system call. The values of
+ these macros are gotten from Linux Kernel source. */
+#define I386_RECORD_SIZE__old_kernel_stat 32
+#define I386_RECORD_SIZE_tms 16
+#define I386_RECORD_SIZE_loff_t 8
+#define I386_RECORD_SIZE_flock 16
+#define I386_RECORD_SIZE_oldold_utsname 45
+#define I386_RECORD_SIZE_ustat 20
+#define I386_RECORD_SIZE_old_sigaction 140
+#define I386_RECORD_SIZE_old_sigset_t 128
+#define I386_RECORD_SIZE_rlimit 8
+#define I386_RECORD_SIZE_rusage 72
+#define I386_RECORD_SIZE_timeval 8
+#define I386_RECORD_SIZE_timezone 8
+#define I386_RECORD_SIZE_old_gid_t 2
+#define I386_RECORD_SIZE_old_uid_t 2
+#define I386_RECORD_SIZE_fd_set 128
+#define I386_RECORD_SIZE_dirent 268
+#define I386_RECORD_SIZE_dirent64 276
+#define I386_RECORD_SIZE_statfs 64
+#define I386_RECORD_SIZE_statfs64 84
+#define I386_RECORD_SIZE_sockaddr 16
+#define I386_RECORD_SIZE_int 4
+#define I386_RECORD_SIZE_long 4
+#define I386_RECORD_SIZE_ulong 4
+#define I386_RECORD_SIZE_msghdr 28
+#define I386_RECORD_SIZE_itimerval 16
+#define I386_RECORD_SIZE_stat 88
+#define I386_RECORD_SIZE_old_utsname 325
+#define I386_RECORD_SIZE_rusage 72
+#define I386_RECORD_SIZE_sysinfo 64
+#define I386_RECORD_SIZE_msqid_ds 88
+#define I386_RECORD_SIZE_shmid_ds 84
+#define I386_RECORD_SIZE_new_utsname 390
+#define I386_RECORD_SIZE_timex 128
+#define I386_RECORD_SIZE_mem_dqinfo 24
+#define I386_RECORD_SIZE_if_dqblk 68
+#define I386_RECORD_SIZE_fs_quota_stat 68
+#define I386_RECORD_SIZE_timespec 8
+#define I386_RECORD_SIZE_pollfd 8
+#define I386_RECORD_SIZE_NFS_FHSIZE 32
+#define I386_RECORD_SIZE_knfsd_fh 132
+#define I386_RECORD_SIZE_TASK_COMM_LEN 16
+#define I386_RECORD_SIZE_sigaction 140
+#define I386_RECORD_SIZE_sigset_t 8
+#define I386_RECORD_SIZE_siginfo_t 128
+#define I386_RECORD_SIZE_cap_user_data_t 12
+#define I386_RECORD_SIZE_stack_t 12
+#define I386_RECORD_SIZE_off_t I386_RECORD_SIZE_long
+#define I386_RECORD_SIZE_stat64 96
+#define I386_RECORD_SIZE_gid_t 2
+#define I386_RECORD_SIZE_uid_t 2
+#define I386_RECORD_SIZE_uid_t 2
+#define I386_RECORD_SIZE_PAGE_SIZE 4096
+#define I386_RECORD_SIZE_flock64 24
+#define I386_RECORD_SIZE_user_desc 16
+#define I386_RECORD_SIZE_io_event 32
+#define I386_RECORD_SIZE_iocb 64
+#define I386_RECORD_SIZE_epoll_event 12
+#define I386_RECORD_SIZE_itimerspec (I386_RECORD_SIZE_timespec * 2)
+#define I386_RECORD_SIZE_mq_attr 32
+#define I386_RECORD_SIZE_siginfo 128
+#define I386_RECORD_SIZE_rusage 72
+
+/* These macros are the values of the first argument of system call
+ "sys_ptrace". The values of these macros are gotten from Linux Kernel
+ source. */
+#define I386_RECORD_PTRACE_PEEKTEXT 1
+#define I386_RECORD_PTRACE_PEEKDATA 2
+#define I386_RECORD_PTRACE_PEEKUSR 3
+
+/* These macros are the values of the second argument of system call
+ "sys_ioctl". The values of these macros are gotten from Linux Kernel
+ source. */
+#define I386_RECORD_FIONCLEX 0x5450
+#define I386_RECORD_FIOCLEX 0x5451
+#define I386_RECORD_FIONBIO 0x5421
+#define I386_RECORD_FIOASYNC 0x5452
+#define I386_RECORD_FIOQSIZE 0x5460
+
+/* These macros are the values of the first argument of system call
+ "sys_socketcall". The values of these macros are gotten from Linux Kernel
+ source. */
+#define I386_RECORD_SYS_SOCKET 1
+#define I386_RECORD_SYS_BIND 2
+#define I386_RECORD_SYS_CONNECT 3
+#define I386_RECORD_SYS_LISTEN 4
+#define I386_RECORD_SYS_ACCEPT 5
+#define I386_RECORD_SYS_GETSOCKNAME 6
+#define I386_RECORD_SYS_GETPEERNAME 7
+#define I386_RECORD_SYS_SOCKETPAIR 8
+#define I386_RECORD_SYS_SEND 9
+#define I386_RECORD_SYS_RECV 10
+#define I386_RECORD_SYS_SENDTO 11
+#define I386_RECORD_SYS_RECVFROM 12
+#define I386_RECORD_SYS_SHUTDOWN 13
+#define I386_RECORD_SYS_SETSOCKOPT 14
+#define I386_RECORD_SYS_GETSOCKOPT 15
+#define I386_RECORD_SYS_SENDMSG 16
+#define I386_RECORD_SYS_RECVMSG 17
+
+/* These macros are the values of the first argument of system call
+ "sys_ipc". The values of these macros are gotten from Linux Kernel source. */
+#define I386_RECORD_SEMOP 1
+#define I386_RECORD_SEMGET 2
+#define I386_RECORD_SEMCTL 3
+#define I386_RECORD_SEMTIMEDOP 4
+#define I386_RECORD_MSGSND 11
+#define I386_RECORD_MSGRCV 12
+#define I386_RECORD_MSGGET 13
+#define I386_RECORD_MSGCTL 14
+#define I386_RECORD_SHMAT 21
+#define I386_RECORD_SHMDT 22
+#define I386_RECORD_SHMGET 23
+#define I386_RECORD_SHMCTL 24
+
+/* These macros are the values of the first argument of system call
+ "sys_quotactl". The values of these macros are gotten from Linux Kernel
+ source. */
+#define I386_RECORD_Q_GETFMT 0x800004
+#define I386_RECORD_Q_GETINFO 0x800005
+#define I386_RECORD_Q_GETQUOTA 0x800007
+#define I386_RECORD_Q_XGETQSTAT (('5'<<8)+(5))
+#define I386_RECORD_Q_XGETQUOTA (('3'<<8)+(3))
+
+/* Parse the arguments of current system call instruction and record the
+ values of the registers and memory that will be changed in current system
+ call instruction to "record_arch_list". This instruction is "int 0x80" (Linux
+ Kernel2.4) or "sysenter" (Linux Kernel 2.6).
+ Return -1 if something wrong. */
+static int
+i386_linux_intx80_sysenter_record (void)
+{
+ uint32_t tmpu32;
+
+ regcache_raw_read (record_regcache, I386_EAX_REGNUM, (gdb_byte *) & tmpu32);
+ switch (tmpu32)
+ {
+ /* sys_restart_syscall */
+ case 0:
+ {
+ int q;
+ target_terminal_ours ();
+ q =
+ yquery (_
+ ("The next instruction is syscall restart. It will restart the computer. Do you want to pause the program."));
+ target_terminal_inferior ();
+ if (q)
+ {
+ return (1);
+ }
+ }
+ break;
+
+ /* sys_exit */
+ case 1:
+ {
+ int q;
+ target_terminal_ours ();
+ q =
+ yquery (_
+ ("The next instruction is syscall exit. It will make the program exit. Do you want to pause the program."));
+ target_terminal_inferior ();
+ if (q)
+ {
+ return (1);
+ }
+ }
+ break;
+
+ /* sys_fork */
+ case 2:
+ break;
+
+ /* sys_read */
+ case 3:
+ {
+ uint32_t addr, count;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & addr);
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & count);
+ if (record_arch_list_add_mem (addr, count))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_write */
+ case 4:
+ /* sys_open */
+ case 5:
+ /* sys_close */
+ case 6:
+ /* sys_waitpid */
+ case 7:
+ /* sys_creat */
+ case 8:
+ /* sys_link */
+ case 9:
+ /* sys_unlink */
+ case 10:
+ /* sys_execve */
+ case 11:
+ /* sys_chdir */
+ case 12:
+ /* sys_time */
+ case 13:
+ /* sys_mknod */
+ case 14:
+ /* sys_chmod */
+ case 15:
+ /* sys_lchown16 */
+ case 16:
+ /* sys_ni_syscall */
+ case 17:
+ break;
+
+ /* sys_stat */
+ case 18:
+ /* sys_fstat */
+ case 28:
+ /* sys_lstat */
+ case 84:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE__old_kernel_stat))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_lseek */
+ case 19:
+ /* sys_getpid */
+ case 20:
+ /* sys_mount */
+ case 21:
+ /* sys_oldumount */
+ case 22:
+ /* sys_setuid16 */
+ case 23:
+ /* sys_getuid16 */
+ case 24:
+ /* sys_stime */
+ case 25:
+ break;
+
+ /* sys_ptrace */
+ case 26:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 == I386_RECORD_PTRACE_PEEKTEXT
+ || tmpu32 == I386_RECORD_PTRACE_PEEKDATA
+ || tmpu32 == I386_RECORD_PTRACE_PEEKUSR)
+ {
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, 4))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_alarm */
+ case 27:
+ /* sys_pause */
+ case 29:
+ /* sys_utime */
+ case 30:
+ /* sys_ni_syscall */
+ case 31:
+ /* sys_ni_syscall */
+ case 32:
+ /* sys_access */
+ case 33:
+ /* sys_nice */
+ case 34:
+ /* sys_ni_syscall */
+ case 35:
+ /* sys_sync */
+ case 36:
+ /* sys_kill */
+ case 37:
+ /* sys_rename */
+ case 38:
+ /* sys_mkdir */
+ case 39:
+ /* sys_rmdir */
+ case 40:
+ /* sys_dup */
+ case 41:
+ /* sys_pipe */
+ case 42:
+ break;
+
+ /* sys_times */
+ case 43:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_tms))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_ni_syscall */
+ case 44:
+ /* sys_brk */
+ case 45:
+ /* sys_setgid16 */
+ case 46:
+ /* sys_getgid16 */
+ case 47:
+ /* sys_signal */
+ case 48:
+ /* sys_geteuid16 */
+ case 49:
+ /* sys_getegid16 */
+ case 50:
+ /* sys_acct */
+ case 51:
+ /* sys_umount */
+ case 52:
+ /* sys_ni_syscall */
+ case 53:
+ break;
+
+ /* sys_ioctl */
+ case 54:
+ /* XXX */
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ switch (tmpu32)
+ {
+ case I386_RECORD_FIOCLEX:
+ case I386_RECORD_FIONCLEX:
+ case I386_RECORD_FIONBIO:
+ case I386_RECORD_FIOASYNC:
+ break;
+ case I386_RECORD_FIOQSIZE:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+ {
+ return (-1);
+ }
+ break;
+ default:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support ioctl request 0x%08x\n"),
+ tmpu32);
+ return (-1);
+ break;
+ }
+ break;
+
+ /* sys_fcntl */
+ case 55:
+ /* XXX */
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ sys_fcntl:
+ if (tmpu32 == F_GETLK)
+ {
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_flock))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_ni_syscall */
+ case 56:
+ /* sys_setpgid */
+ case 57:
+ /* sys_ni_syscall */
+ case 58:
+ break;
+
+ /* sys_olduname */
+ case 59:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_oldold_utsname))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_umask */
+ case 60:
+ /* sys_chroot */
+ case 61:
+ break;
+
+ /* sys_ustat */
+ case 62:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_ustat))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_dup2 */
+ case 63:
+ /* sys_getppid */
+ case 64:
+ /* sys_getpgrp */
+ case 65:
+ /* sys_setsid */
+ case 66:
+ break;
+
+ /* sys_sigaction */
+ case 67:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_sigaction))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_sgetmask */
+ case 68:
+ /* sys_ssetmask */
+ case 69:
+ /* sys_setreuid16 */
+ case 70:
+ /* sys_setregid16 */
+ case 71:
+ /* sys_sigsuspend */
+ case 72:
+ break;
+
+ /* sys_sigpending */
+ case 73:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_sigset_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_sethostname */
+ case 74:
+ /* sys_setrlimit */
+ case 75:
+ break;
+
+ /* sys_old_getrlimit */
+ case 76:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rlimit))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_getrusage */
+ case 77:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rusage))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_gettimeofday */
+ case 78:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timeval))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timezone))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_settimeofday */
+ case 79:
+ break;
+
+ /* sys_getgroups16 */
+ case 80:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_setgroups16 */
+ case 81:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* old_select */
+ case 82:
+ {
+ /*
+ struct sel_arg_struct {
+ unsigned long n;
+ fd_set *inp;
+ fd_set *outp;
+ fd_set *exp;
+ struct timeval *tvp;
+ };
+ */
+ struct sel_arg_struct
+ {
+ uint32_t n;
+ uint32_t inp;
+ uint32_t outp;
+ uint32_t exp;
+ uint32_t tvp;
+ } sel;
+
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ if (target_read_memory (tmpu32, (gdb_byte *) & sel, sizeof (sel)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), sizeof (sel));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (sel.inp, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (sel.outp, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (sel.exp, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (sel.tvp, I386_RECORD_SIZE_timeval))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+
+ /* sys_symlink */
+ case 83:
+ break;
+
+ /* sys_readlink */
+ case 85:
+ {
+ uint32_t len;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & len);
+ if (record_arch_list_add_mem (tmpu32, len))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_uselib */
+ case 86:
+ /* sys_swapon */
+ case 87:
+ break;
+
+ /* sys_reboot */
+ case 88:
+ {
+ int q;
+ target_terminal_ours ();
+ q =
+ yquery (_
+ ("The next instruction is syscall reboot. It will restart the computer. Do you want to pause the program."));
+ target_terminal_inferior ();
+ if (q)
+ {
+ return (1);
+ }
+ }
+ break;
+
+ /* old_readdir */
+ case 89:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_dirent))
+ {
+ return (-1);
+ }
+ break;
+
+ /* old_mmap */
+ case 90:
+ break;
+
+ /* sys_munmap */
+ case 91:
+ {
+ int q;
+ uint32_t len;
+
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & len);
+ target_terminal_ours ();
+ q =
+ yquery (_
+ ("The next instruction is syscall munmap. It will free the memory addr = 0x%s len = %d. Do you want to pause the program."),
+ paddr_nz (tmpu32), len);
+ target_terminal_inferior ();
+ if (q)
+ {
+ return (1);
+ }
+ }
+ break;
+
+ /* sys_truncate */
+ case 92:
+ /* sys_ftruncate */
+ case 93:
+ /* sys_fchmod */
+ case 94:
+ /* sys_fchown16 */
+ case 95:
+ /* sys_getpriority */
+ case 96:
+ /* sys_setpriority */
+ case 97:
+ /* sys_ni_syscall */
+ case 98:
+ break;
+
+ /* sys_statfs */
+ case 99:
+ /* sys_fstatfs */
+ case 100:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_statfs))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_ioperm */
+ case 101:
+ break;
+
+ /* sys_socketcall */
+ case 102:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ switch (tmpu32)
+ {
+ case I386_RECORD_SYS_SOCKET:
+ case I386_RECORD_SYS_BIND:
+ case I386_RECORD_SYS_CONNECT:
+ case I386_RECORD_SYS_LISTEN:
+ break;
+ case I386_RECORD_SYS_ACCEPT:
+ case I386_RECORD_SYS_GETSOCKNAME:
+ case I386_RECORD_SYS_GETPEERNAME:
+ {
+ uint32_t a[3];
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), sizeof (a));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[1], I386_RECORD_SIZE_sockaddr))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[2], I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+
+ case I386_RECORD_SYS_SOCKETPAIR:
+ {
+ uint32_t a[4];
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), sizeof (a));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[3], I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+ case I386_RECORD_SYS_SEND:
+ case I386_RECORD_SYS_SENDTO:
+ break;
+ case I386_RECORD_SYS_RECV:
+ {
+ uint32_t a[3];
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), sizeof (a));
+ return (-1);
+ }
+ if (a[2])
+ {
+ if (target_read_memory
+ (a[2], (gdb_byte *) & (a[2]), sizeof (a[2])))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (a[2]), sizeof (a[2]));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[1], a[2]))
+ {
+ return (-1);
+ }
+ }
+ }
+ }
+ break;
+ case I386_RECORD_SYS_RECVFROM:
+ {
+ uint32_t a[6];
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), sizeof (a));
+ return (-1);
+ }
+ if (a[2])
+ {
+ if (target_read_memory
+ (a[2], (gdb_byte *) & (a[2]), sizeof (a[2])))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (a[2]), sizeof (a[2]));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[1], a[2]))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[4], I386_RECORD_SIZE_sockaddr))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[5], I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ }
+ }
+ }
+ break;
+ case I386_RECORD_SYS_SHUTDOWN:
+ case I386_RECORD_SYS_SETSOCKOPT:
+ break;
+ case I386_RECORD_SYS_GETSOCKOPT:
+ {
+ uint32_t a[5];
+ uint32_t av;
+
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), sizeof (a));
+ return (-1);
+ }
+ if (a[4])
+ {
+ if (target_read_memory
+ (a[4], (gdb_byte *) & av, sizeof (av)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (a[4]), sizeof (av));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[3], av))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[4], I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ }
+ }
+ }
+ break;
+ case I386_RECORD_SYS_SENDMSG:
+ break;
+ case I386_RECORD_SYS_RECVMSG:
+ {
+ uint32_t a[2], i;
+ struct record_msghdr
+ {
+ uint32_t msg_name;
+ uint32_t msg_namelen;
+ uint32_t msg_iov;
+ uint32_t msg_iovlen;
+ uint32_t msg_control;
+ uint32_t msg_controllen;
+ uint32_t msg_flags;
+ } rec;
+ struct record_iovec
+ {
+ uint32_t iov_base;
+ uint32_t iov_len;
+ } iov;
+
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ if (target_read_memory (tmpu32, (gdb_byte *) a, sizeof (a)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), sizeof (a));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (a[1], I386_RECORD_SIZE_msghdr))
+ {
+ return (-1);
+ }
+ if (a[1])
+ {
+ if (target_read_memory
+ (a[1], (gdb_byte *) & rec, sizeof (rec)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (a[1]), sizeof (rec));
+ return (-1);
+ }
+ if (record_arch_list_add_mem
+ (rec.msg_name, rec.msg_namelen))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem
+ (rec.msg_control, rec.msg_controllen))
+ {
+ return (-1);
+ }
+ if (rec.msg_iov)
+ {
+ for (i = 0; i < rec.msg_iovlen; i++)
+ {
+ if (target_read_memory
+ (rec.msg_iov, (gdb_byte *) & iov,
+ sizeof (iov)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (rec.msg_iov),
+ sizeof (iov));
+ return (-1);
+ }
+ if (record_arch_list_add_mem
+ (iov.iov_base, iov.iov_len))
+ {
+ return (-1);
+ }
+ rec.msg_iov += sizeof (struct record_iovec);
+ }
+ }
+ }
+ }
+ }
+ break;
+ default:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support socketcall call 0x%08x\n"),
+ tmpu32);
+ return (-1);
+ break;
+ }
+ break;
+
+ /* sys_syslog */
+ case 103:
+ break;
+
+ /* sys_setitimer */
+ case 104:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerval))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_getitimer */
+ case 105:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerval))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_newstat */
+ case 106:
+ /* sys_newlstat */
+ case 107:
+ /* sys_newfstat */
+ case 108:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stat))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_uname */
+ case 109:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_utsname))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_iopl */
+ case 110:
+ /* sys_vhangup */
+ case 111:
+ /* sys_ni_syscall */
+ case 112:
+ /* sys_vm86old */
+ case 113:
+ break;
+
+ /* sys_wait4 */
+ case 114:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rusage))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_swapoff */
+ case 115:
+ break;
+
+ /* sys_sysinfo */
+ case 116:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_sysinfo))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_ipc */
+ case 117:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ switch (tmpu32)
+ {
+ case I386_RECORD_MSGRCV:
+ {
+ int32_t second;
+ uint32_t ptr;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & second);
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & ptr);
+ if (record_arch_list_add_mem (ptr, second + I386_RECORD_SIZE_long))
+ {
+ return (-1);
+ }
+ }
+ break;
+ case I386_RECORD_MSGCTL:
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_msqid_ds))
+ {
+ return (-1);
+ }
+ break;
+ case I386_RECORD_SHMAT:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_ulong))
+ {
+ return (-1);
+ }
+ break;
+ case I386_RECORD_SHMCTL:
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_shmid_ds))
+ {
+ return (-1);
+ }
+ break;
+ }
+ break;
+
+ /* sys_fsync */
+ case 118:
+ /* sys_sigreturn */
+ case 119:
+ /* sys_clone */
+ case 120:
+ /* sys_setdomainname */
+ case 121:
+ break;
+
+ /* sys_newuname */
+ case 122:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_new_utsname))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_modify_ldt */
+ case 123:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 == 0 || tmpu32 == 2)
+ {
+ uint32_t ptr, bytecount;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & ptr);
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & bytecount);
+ if (record_arch_list_add_mem (ptr, bytecount))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_adjtimex */
+ case 124:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timex))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_mprotect */
+ case 125:
+ break;
+
+ /* sys_sigprocmask */
+ case 126:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_sigset_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_ni_syscall */
+ case 127:
+ /* sys_init_module */
+ case 128:
+ /* sys_delete_module */
+ case 129:
+ /* sys_ni_syscall */
+ case 130:
+ break;
+
+ /* sys_quotactl */
+ case 131:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ switch (tmpu32)
+ {
+ case I386_RECORD_Q_GETFMT:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, 4))
+ {
+ return (-1);
+ }
+ break;
+ case I386_RECORD_Q_GETINFO:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_mem_dqinfo))
+ {
+ return (-1);
+ }
+ break;
+ case I386_RECORD_Q_GETQUOTA:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_if_dqblk))
+ {
+ return (-1);
+ }
+ break;
+ case I386_RECORD_Q_XGETQSTAT:
+ case I386_RECORD_Q_XGETQUOTA:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fs_quota_stat))
+ {
+ return (-1);
+ }
+ break;
+ }
+ break;
+
+ /* sys_getpgid */
+ case 132:
+ /* sys_fchdir */
+ case 133:
+ /* sys_bdflush */
+ case 134:
+ break;
+
+ /* sys_sysfs */
+ case 135:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 == 2)
+ {
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ /*XXX the size of memory is not very clear */
+ if (record_arch_list_add_mem (tmpu32, 10))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_personality */
+ case 136:
+ /* sys_ni_syscall */
+ case 137:
+ /* sys_setfsuid16 */
+ case 138:
+ /* sys_setfsgid16 */
+ case 139:
+ break;
+
+ /* sys_llseek */
+ case 140:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_getdents */
+ case 141:
+ {
+ uint32_t count;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & count);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_dirent * count))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_select */
+ case 142:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timeval))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_flock */
+ case 143:
+ /* sys_msync */
+ case 144:
+ break;
+
+ /* sys_readv */
+ case 145:
+ {
+ uint32_t vec;
+ uint32_t vlen;
+ struct record_iovec
+ {
+ uint32_t iov_base;
+ uint32_t iov_len;
+ } iov;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & vec);
+ if (vec)
+ {
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & vlen);
+ for (tmpu32 = 0; tmpu32 < vlen; tmpu32++)
+ {
+ if (target_read_memory
+ (vec, (gdb_byte *) & iov, sizeof (struct record_iovec)))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (vec),
+ sizeof (struct record_iovec));
+ return (-1);
+ }
+ if (record_arch_list_add_mem (iov.iov_base, iov.iov_len))
+ {
+ return (-1);
+ }
+ vec += sizeof (struct record_iovec);
+ }
+ }
+ }
+ break;
+
+ /* sys_writev */
+ case 146:
+ /* sys_getsid */
+ case 147:
+ /* sys_fdatasync */
+ case 148:
+ /* sys_sysctl */
+ case 149:
+ /* sys_mlock */
+ case 150:
+ /* sys_munlock */
+ case 151:
+ /* sys_mlockall */
+ case 152:
+ /* sys_munlockall */
+ case 153:
+ /* sys_sched_setparam */
+ case 154:
+ break;
+
+ /* sys_sched_getparam */
+ case 155:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_sched_setscheduler */
+ case 156:
+ /* sys_sched_getscheduler */
+ case 157:
+ /* sys_sched_yield */
+ case 158:
+ /* sys_sched_get_priority_max */
+ case 159:
+ /* sys_sched_get_priority_min */
+ case 160:
+ break;
+
+ /* sys_sched_rr_get_interval */
+ case 161:
+ /* sys_nanosleep */
+ case 162:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_mremap */
+ case 163:
+ /* sys_setresuid16 */
+ case 164:
+ break;
+
+ /* sys_getresuid16 */
+ case 165:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_uid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_uid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_uid_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_vm86 */
+ case 166:
+ /* sys_ni_syscall */
+ case 167:
+ break;
+
+ /* sys_poll */
+ case 168:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t nfds;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & nfds);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_pollfd * nfds))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_nfsservctl */
+ case 169:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 == 7 || tmpu32 == 8)
+ {
+ uint32_t rsize;
+ if (tmpu32 == 7)
+ {
+ rsize = I386_RECORD_SIZE_NFS_FHSIZE;
+ }
+ else
+ {
+ rsize = I386_RECORD_SIZE_knfsd_fh;
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, rsize))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_setresgid16 */
+ case 170:
+ break;
+
+ /* sys_getresgid16 */
+ case 171:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_old_gid_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_prctl */
+ case 172:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ switch (tmpu32)
+ {
+ case 2:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ break;
+ case 16:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_TASK_COMM_LEN))
+ {
+ return (-1);
+ }
+ break;
+ }
+ break;
+
+ /* sys_rt_sigreturn */
+ case 173:
+ break;
+
+ /* sys_rt_sigaction */
+ case 174:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_sigaction))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_rt_sigprocmask */
+ case 175:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_sigset_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_rt_sigpending */
+ case 176:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t sigsetsize;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & sigsetsize);
+ if (record_arch_list_add_mem (tmpu32, sigsetsize))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_rt_sigtimedwait */
+ case 177:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_siginfo_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_rt_sigqueueinfo */
+ case 178:
+ /* sys_rt_sigsuspend */
+ case 179:
+ break;
+
+ /* sys_pread64 */
+ case 180:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t count;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & count);
+ if (record_arch_list_add_mem (tmpu32, count))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_pwrite64 */
+ case 181:
+ /* sys_chown16 */
+ case 182:
+ break;
+
+ /* sys_getcwd */
+ case 183:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t size;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & size);
+ if (record_arch_list_add_mem (tmpu32, size))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_capget */
+ case 184:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_cap_user_data_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_capset */
+ case 185:
+ break;
+
+ /* sys_sigaltstack */
+ case 186:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stack_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_sendfile */
+ case 187:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_off_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_ni_syscall */
+ case 188:
+ /* sys_ni_syscall */
+ case 189:
+ /* sys_vfork */
+ case 190:
+ break;
+
+ /* sys_getrlimit */
+ case 191:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rlimit))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_mmap2 */
+ case 192:
+ break;
+
+ /* sys_truncate64 */
+ case 193:
+ /* sys_ftruncate64 */
+ case 194:
+ break;
+
+ /* sys_stat64 */
+ case 195:
+ /* sys_lstat64 */
+ case 196:
+ /* sys_fstat64 */
+ case 197:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stat64))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_lchown */
+ case 198:
+ /* sys_getuid */
+ case 199:
+ /* sys_getgid */
+ case 200:
+ /* sys_geteuid */
+ case 201:
+ /* sys_getegid */
+ case 202:
+ /* sys_setreuid */
+ case 203:
+ /* sys_setregid */
+ case 204:
+ break;
+
+ /* sys_getgroups */
+ case 205:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ int gidsetsize;
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & gidsetsize);
+ if (record_arch_list_add_mem
+ (tmpu32, I386_RECORD_SIZE_gid_t * gidsetsize))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_setgroups */
+ case 206:
+ /* sys_fchown */
+ case 207:
+ /* sys_setresuid */
+ case 208:
+ break;
+
+ /* sys_getresuid */
+ case 209:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_uid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_uid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_uid_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_setresgid */
+ case 210:
+ break;
+
+ /* sys_getresgid */
+ case 211:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_gid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_gid_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_gid_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_chown */
+ case 212:
+ /* sys_setuid */
+ case 213:
+ /* sys_setgid */
+ case 214:
+ /* sys_setfsuid */
+ case 215:
+ /* sys_setfsgid */
+ case 216:
+ /* sys_pivot_root */
+ case 217:
+ break;
+
+ /* sys_mincore */
+ case 218:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_PAGE_SIZE))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_madvise */
+ case 219:
+ break;
+
+ /* sys_getdents64 */
+ case 220:
+ {
+ uint32_t count;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & count);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_dirent64 * count))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_fcntl64 */
+ case 221:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ switch (tmpu32)
+ {
+ case F_GETLK64:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_flock64))
+ {
+ return (-1);
+ }
+ break;
+ case F_SETLK64:
+ case F_SETLKW64:
+ break;
+ default:
+ goto sys_fcntl;
+ break;
+ }
+ break;
+
+ /* sys_ni_syscall */
+ case 222:
+ /* sys_ni_syscall */
+ case 223:
+ /* sys_gettid */
+ case 224:
+ /* sys_readahead */
+ case 225:
+ /* sys_setxattr */
+ case 226:
+ /* sys_lsetxattr */
+ case 227:
+ /* sys_fsetxattr */
+ case 228:
+ break;
+
+ /* sys_getxattr */
+ case 229:
+ /* sys_lgetxattr */
+ case 230:
+ /* sys_fgetxattr */
+ case 231:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t size;
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & size);
+ if (record_arch_list_add_mem (tmpu32, size))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_listxattr */
+ case 232:
+ /* sys_llistxattr */
+ case 233:
+ /* sys_flistxattr */
+ case 234:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t size;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & size);
+ if (record_arch_list_add_mem (tmpu32, size))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_removexattr */
+ case 235:
+ /* sys_lremovexattr */
+ case 236:
+ /* sys_fremovexattr */
+ case 237:
+ /* sys_tkill */
+ case 238:
+ break;
+
+ /* sys_sendfile64 */
+ case 239:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_futex */
+ case 240:
+ /* sys_sched_setaffinity */
+ case 241:
+ break;
+
+ /* sys_sched_getaffinity */
+ case 242:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t len;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & len);
+ if (record_arch_list_add_mem (tmpu32, len))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_set_thread_area */
+ case 243:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_get_thread_area */
+ case 244:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_user_desc))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_io_setup */
+ case 245:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_long))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_io_destroy */
+ case 246:
+ break;
+
+ /* sys_io_getevents */
+ case 247:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ int32_t nr;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & nr);
+ if (record_arch_list_add_mem (tmpu32, nr * I386_RECORD_SIZE_io_event))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_io_submit */
+ case 248:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ int32_t i, nr;
+ uint32_t *iocbp;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & nr);
+ iocbp = (uint32_t *) alloca (nr * I386_RECORD_SIZE_int);
+ if (target_read_memory
+ (tmpu32, (gdb_byte *) iocbp, nr * I386_RECORD_SIZE_int))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (tmpu32), nr * I386_RECORD_SIZE_int);
+ return (-1);
+ }
+ for (i = 0; i < nr; i++)
+ {
+ if (record_arch_list_add_mem (iocbp[i], I386_RECORD_SIZE_iocb))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+
+ /* sys_io_cancel */
+ case 249:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_io_event))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_fadvise64 */
+ case 250:
+ /* sys_ni_syscall */
+ case 251:
+ break;
+
+ /* sys_exit_group */
+ case 252:
+ {
+ int q;
+ target_terminal_ours ();
+ q =
+ yquery (_
+ ("The next instruction is syscall exit_group. It will make the program exit. Do you want to pause the program."));
+ target_terminal_inferior ();
+ if (q)
+ {
+ return (1);
+ }
+ }
+ break;
+
+ /* sys_lookup_dcookie */
+ case 253:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t len;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & len);
+ if (record_arch_list_add_mem (tmpu32, len))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_epoll_create */
+ case 254:
+ /* sys_epoll_ctl */
+ case 255:
+ break;
+
+ /* sys_epoll_wait */
+ case 256:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ int32_t maxevents;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & maxevents);
+ if (record_arch_list_add_mem
+ (tmpu32, maxevents * I386_RECORD_SIZE_epoll_event))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_remap_file_pages */
+ case 257:
+ /* sys_set_tid_address */
+ case 258:
+ break;
+
+ /* sys_timer_create */
+ case 259:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_timer_settime */
+ case 260:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerspec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_timer_gettime */
+ case 261:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_itimerspec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_timer_getoverrun */
+ case 262:
+ /* sys_timer_delete */
+ case 263:
+ /* sys_clock_settime */
+ case 264:
+ break;
+
+ /* sys_clock_gettime */
+ case 265:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_clock_getres */
+ case 266:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_clock_nanosleep */
+ case 267:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_statfs64 */
+ case 268:
+ /* sys_fstatfs64 */
+ case 269:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_statfs64))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_tgkill */
+ case 270:
+ /* sys_utimes */
+ case 271:
+ /* sys_fadvise64_64 */
+ case 272:
+ /* sys_ni_syscall */
+ case 273:
+ /* sys_mbind */
+ case 274:
+ break;
+
+ /* sys_get_mempolicy */
+ case 275:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t maxnode;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & maxnode);
+ if (record_arch_list_add_mem (tmpu32, maxnode * I386_RECORD_SIZE_long))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_set_mempolicy */
+ case 276:
+ /* sys_mq_open */
+ case 277:
+ /* sys_mq_unlink */
+ case 278:
+ /* sys_mq_timedsend */
+ case 279:
+ break;
+
+ /* sys_mq_timedreceive */
+ case 280:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t msg_len;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & msg_len);
+ if (record_arch_list_add_mem (tmpu32, msg_len))
+ {
+ return (-1);
+ }
+ }
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_mq_notify */
+ case 281:
+ break;
+
+ /* sys_mq_getsetattr */
+ case 282:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_mq_attr))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_kexec_load */
+ case 283:
+ break;
+
+ /* sys_waitid */
+ case 284:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_siginfo))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_rusage))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_ni_syscall */
+ case 285:
+ /* sys_add_key */
+ case 286:
+ /* sys_request_key */
+ case 287:
+ break;
+
+ /* sys_keyctl */
+ case 288:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 == 6 || tmpu32 == 11)
+ {
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t buflen;
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & buflen);
+ if (record_arch_list_add_mem (tmpu32, buflen))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+
+ /* sys_ioprio_set */
+ case 289:
+ /* sys_ioprio_get */
+ case 290:
+ /* sys_inotify_init */
+ case 291:
+ /* sys_inotify_add_watch */
+ case 292:
+ /* sys_inotify_rm_watch */
+ case 293:
+ /* sys_migrate_pages */
+ case 294:
+ /* sys_openat */
+ case 295:
+ /* sys_mkdirat */
+ case 296:
+ /* sys_mknodat */
+ case 297:
+ /* sys_fchownat */
+ case 298:
+ /* sys_futimesat */
+ case 299:
+ break;
+
+ /* sys_fstatat64 */
+ case 300:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_stat64))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_unlinkat */
+ case 301:
+ /* sys_renameat */
+ case 302:
+ /* sys_linkat */
+ case 303:
+ /* sys_symlinkat */
+ case 304:
+ break;
+
+ /* sys_readlinkat */
+ case 305:
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ int32_t bufsiz;
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & bufsiz);
+ if (record_arch_list_add_mem (tmpu32, bufsiz))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_fchmodat */
+ case 306:
+ /* sys_faccessat */
+ case 307:
+ break;
+
+ /* sys_pselect6 */
+ case 308:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_fd_set))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_ppoll */
+ case 309:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t nfds;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & nfds);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_pollfd * nfds))
+ {
+ return (-1);
+ }
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_timespec))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_unshare */
+ case 310:
+ /* sys_set_robust_list */
+ case 311:
+ break;
+
+ /* sys_get_robust_list */
+ case 312:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_splice */
+ case 313:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_loff_t))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_sync_file_range */
+ case 314:
+ /* sys_tee */
+ case 315:
+ /* sys_vmsplice */
+ case 316:
+ break;
+
+ /* sys_move_pages */
+ case 317:
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ uint32_t nr_pages;
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & nr_pages);
+ if (record_arch_list_add_mem (tmpu32, nr_pages * I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* sys_getcpu */
+ case 318:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_int))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem (tmpu32, I386_RECORD_SIZE_ulong * 2))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sys_epoll_pwait */
+ case 319:
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32)
+ {
+ int32_t maxevents;
+ regcache_raw_read (record_regcache, I386_EDX_REGNUM,
+ (gdb_byte *) & maxevents);
+ if (record_arch_list_add_mem
+ (tmpu32, maxevents * I386_RECORD_SIZE_epoll_event))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ default:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support syscall number 0x%08x\n"),
+ tmpu32);
+ return (-1);
+ break;
+ }
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+
+ return (0);
+}
+
\f
/* The register sets used in GNU/Linux ELF core-dumps are identical to
@@ -429,6 +2959,9 @@ i386_linux_init_abi (struct gdbarch_info
tdep->sc_reg_offset = i386_linux_sc_reg_offset;
tdep->sc_num_regs = ARRAY_SIZE (i386_linux_sc_reg_offset);
+ tdep->i386_intx80_record = i386_linux_intx80_sysenter_record;
+ tdep->i386_sysenter_record = i386_linux_intx80_sysenter_record;
+
/* N_FUN symbols in shared libaries have 0 for their values and need
to be relocated. */
set_gdbarch_sofun_address_maybe_missing (gdbarch, 1);
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -49,6 +49,9 @@
#include "i386-tdep.h"
#include "i387-tdep.h"
+#include "record.h"
+#include <stdint.h>
+
/* Register names. */
static char *i386_register_names[] =
@@ -2315,154 +2318,2682 @@ i386_fetch_pointer_argument (struct fram
return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
}
-\f
-static struct gdbarch *
-i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
-{
- struct gdbarch_tdep *tdep;
- struct gdbarch *gdbarch;
- /* If there is already a candidate, use it. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return arches->gdbarch;
+#define PREFIX_REPZ 0x01
+#define PREFIX_REPNZ 0x02
+#define PREFIX_LOCK 0x04
+#define PREFIX_DATA 0x08
+#define PREFIX_ADDR 0x10
+
+/* operand size */
+enum
+{
+ OT_BYTE = 0,
+ OT_WORD,
+ OT_LONG,
+};
- /* Allocate space for the new architecture. */
- tdep = XCALLOC (1, struct gdbarch_tdep);
- gdbarch = gdbarch_alloc (&info, tdep);
+/* i386 arith/logic operations */
+enum
+{
+ OP_ADDL,
+ OP_ORL,
+ OP_ADCL,
+ OP_SBBL,
+ OP_ANDL,
+ OP_SUBL,
+ OP_XORL,
+ OP_CMPL,
+};
- /* General-purpose registers. */
- tdep->gregset = NULL;
- tdep->gregset_reg_offset = NULL;
- tdep->gregset_num_regs = I386_NUM_GREGS;
- tdep->sizeof_gregset = 0;
+static int aflag = 1;
+static int dflag = 1;
+static int override = 0;
+static uint8_t modrm;
+static uint8_t mod, reg, rm;
+static int ot;
+static CORE_ADDR i386_record_pc;
- /* Floating-point registers. */
- tdep->fpregset = NULL;
- tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+/* Parse "modrm" part in current memory address that i386_record_pc point to.
+ Return -1 if something wrong. */
+static int
+i386_record_modrm (void)
+{
+ if (target_read_memory (i386_record_pc, &modrm, 1))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc++;
+ mod = (modrm >> 6) & 3;
+ reg = (modrm >> 3) & 7;
+ rm = modrm & 7;
- /* The default settings include the FPU registers, the MMX registers
- and the SSE registers. This can be overridden for a specific ABI
- by adjusting the members `st0_regnum', `mm0_regnum' and
- `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
- will show up in the output of "info all-registers". Ideally we
- should try to autodetect whether they are available, such that we
- can prevent "info all-registers" from displaying registers that
- aren't available.
+ return (0);
+}
- NOTE: kevinb/2003-07-13: ... if it's a choice between printing
- [the SSE registers] always (even when they don't exist) or never
- showing them to the user (even when they do exist), I prefer the
- former over the latter. */
+/* Get the memory address that current instruction write to and set it to
+ the argument "addr".
+ Return -1 if something wrong. */
+static int
+i386_record_lea_modrm_addr (uint32_t * addr)
+{
+ uint8_t tmpu8;
+ uint16_t tmpu16;
+ uint32_t tmpu32;
+
+ *addr = 0;
+ if (aflag)
+ {
+ /* 32 bits */
+ int havesib = 0;
+ uint8_t scale = 0;
+ uint8_t index = 0;
+ uint8_t base = rm;
- tdep->st0_regnum = I386_ST0_REGNUM;
+ if (base == 4)
+ {
+ havesib = 1;
+ if (target_read_memory (i386_record_pc, &tmpu8, 1))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc++;
+ scale = (tmpu8 >> 6) & 3;
+ index = ((tmpu8 >> 3) & 7);
+ base = (tmpu8 & 7);
+ }
- /* The MMX registers are implemented as pseudo-registers. Put off
- calculating the register number for %mm0 until we know the number
- of raw registers. */
- tdep->mm0_regnum = 0;
+ switch (mod)
+ {
+ case 0:
+ if ((base & 7) == 5)
+ {
+ base = 0xff;
+ if (target_read_memory (i386_record_pc, (gdb_byte *) addr, 4))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc += 4;
+ }
+ else
+ {
+ *addr = 0;
+ }
+ break;
+ case 1:
+ if (target_read_memory (i386_record_pc, &tmpu8, 1))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc++;
+ *addr = (int8_t) tmpu8;
+ break;
+ case 2:
+ if (target_read_memory (i386_record_pc, (gdb_byte *) addr, 4))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc += 4;
+ break;
+ }
- /* I386_NUM_XREGS includes %mxcsr, so substract one. */
- tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+ if (base != 0xff)
+ {
+ regcache_raw_read (record_regcache, base, (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ }
- tdep->jb_pc_offset = -1;
- tdep->struct_return = pcc_struct_return;
- tdep->sigtramp_start = 0;
- tdep->sigtramp_end = 0;
- tdep->sigtramp_p = i386_sigtramp_p;
- tdep->sigcontext_addr = NULL;
- tdep->sc_reg_offset = NULL;
- tdep->sc_pc_offset = -1;
- tdep->sc_sp_offset = -1;
+ /* XXX: index == 4 is always invalid */
+ if (havesib && (index != 4 || scale != 0))
+ {
+ regcache_raw_read (record_regcache, index, (gdb_byte *) & tmpu32);
+ *addr += tmpu32 << scale;
+ }
+ }
+ else
+ {
+ /* 16 bits */
+ switch (mod)
+ {
+ case 0:
+ if (rm == 6)
+ {
+ if (target_read_memory
+ (i386_record_pc, (gdb_byte *) & tmpu16, 2))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc += 2;
+ *addr = (int16_t) tmpu16;
+ rm = 0;
+ goto no_rm;
+ }
+ else
+ {
+ *addr = 0;
+ }
+ break;
+ case 1:
+ if (target_read_memory (i386_record_pc, &tmpu8, 1))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc++;
+ *addr = (int8_t) tmpu8;
+ break;
+ case 2:
+ if (target_read_memory (i386_record_pc, (gdb_byte *) & tmpu16, 2))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc += 2;
+ *addr = (int16_t) tmpu16;
+ break;
+ }
- /* The format used for `long double' on almost all i386 targets is
- the i387 extended floating-point format. In fact, of all targets
- in the GCC 2.95 tree, only OSF/1 does it different, and insists
- on having a `long double' that's not `long' at all. */
- set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext);
+ switch (rm)
+ {
+ case 0:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 1:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 2:
+ regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 3:
+ regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 4:
+ regcache_raw_read (record_regcache, I386_ESI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 5:
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 6:
+ regcache_raw_read (record_regcache, I386_EBP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ case 7:
+ regcache_raw_read (record_regcache, I386_EBX_REGNUM,
+ (gdb_byte *) & tmpu32);
+ *addr += tmpu32;
+ break;
+ }
+ *addr &= 0xffff;
+ }
- /* Although the i387 extended floating-point has only 80 significant
- bits, a `long double' actually takes up 96, probably to enforce
- alignment. */
- set_gdbarch_long_double_bit (gdbarch, 96);
+no_rm:
+ return (0);
+}
- /* The default ABI includes general-purpose registers,
- floating-point registers, and the SSE registers. */
- set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
- set_gdbarch_register_name (gdbarch, i386_register_name);
- set_gdbarch_register_type (gdbarch, i386_register_type);
+/* Record the value of the memory that willbe changed in current instruction
+ to "record_arch_list".
+ Return -1 if something wrong. */
+static int
+i386_record_lea_modrm (void)
+{
+ uint32_t addr;
- /* Register numbers of various important registers. */
- set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
- set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
- set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
- set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+ if (override)
+ {
+ printf_unfiltered (_
+ ("record: cann't get the value of the segment register in address 0x%s. Record ignore this change.\n"),
+ paddr_nz (read_pc ()));
+ return (0);
+ }
- /* NOTE: kettenis/20040418: GCC does have two possible register
- numbering schemes on the i386: dbx and SVR4. These schemes
- differ in how they number %ebp, %esp, %eflags, and the
- floating-point registers, and are implemented by the arrays
- dbx_register_map[] and svr4_dbx_register_map in
- gcc/config/i386.c. GCC also defines a third numbering scheme in
- gcc/config/i386.c, which it designates as the "default" register
- map used in 64bit mode. This last register numbering scheme is
- implemented in dbx64_register_map, and is used for AMD64; see
- amd64-tdep.c.
+ if (i386_record_lea_modrm_addr (&addr))
+ {
+ return (-1);
+ }
- Currently, each GCC i386 target always uses the same register
- numbering scheme across all its supported debugging formats
- i.e. SDB (COFF), stabs and DWARF 2. This is because
- gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
- DBX_REGISTER_NUMBER macro which is defined by each target's
- respective config header in a manner independent of the requested
- output debugging format.
+ if (record_arch_list_add_mem (addr, 1 << ot))
+ {
+ return (-1);
+ }
- This does not match the arrangement below, which presumes that
- the SDB and stabs numbering schemes differ from the DWARF and
- DWARF 2 ones. The reason for this arrangement is that it is
- likely to get the numbering scheme for the target's
- default/native debug format right. For targets where GCC is the
- native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
- targets where the native toolchain uses a different numbering
- scheme for a particular debug format (stabs-in-ELF on Solaris)
- the defaults below will have to be overridden, like
- i386_elf_init_abi() does. */
+ return (0);
+}
- /* Use the dbx register numbering scheme for stabs and COFF. */
- set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
- set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+/* Parse the current instruction and record the values of the registers and
+ memory that will be changed in current instruction to "record_arch_list".
+ Return -1 if something wrong. */
+static int
+i386_record (struct gdbarch *gdbarch)
+{
+ int prefixes = 0;
+ uint8_t tmpu8;
+ uint16_t tmpu16;
+ uint32_t tmpu32;
+ uint32_t opcode;
+ int need_dasm = 0;
- /* Use the SVR4 register numbering scheme for DWARF and DWARF 2. */
- set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+ i386_record_pc = read_pc ();
+ aflag = 1;
+ dflag = 1;
+ override = 0;
- /* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
- be in use on any of the supported i386 targets. */
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: i386_record pc = 0x%s\n",
+ paddr_nz (i386_record_pc));
+ }
- set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
+ /* prefixes */
+ while (1)
+ {
+ if (target_read_memory (i386_record_pc, &tmpu8, 1))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc++;
+ switch (tmpu8)
+ {
+ case 0xf3:
+ prefixes |= PREFIX_REPZ;
+ break;
+ case 0xf2:
+ prefixes |= PREFIX_REPNZ;
+ break;
+ case 0xf0:
+ prefixes |= PREFIX_LOCK;
+ break;
+ case 0x2e:
+ override = I386_CS_REGNUM;
+ break;
+ case 0x36:
+ override = I386_SS_REGNUM;
+ break;
+ case 0x3e:
+ override = I386_DS_REGNUM;
+ break;
+ case 0x26:
+ override = I386_ES_REGNUM;
+ break;
+ case 0x64:
+ override = I386_FS_REGNUM;
+ break;
+ case 0x65:
+ override = I386_GS_REGNUM;
+ break;
+ case 0x66:
+ prefixes |= PREFIX_DATA;
+ break;
+ case 0x67:
+ prefixes |= PREFIX_ADDR;
+ break;
+ default:
+ goto out_prefixes;
+ break;
+ }
+ }
+out_prefixes:
+ if (prefixes & PREFIX_DATA)
+ {
+ dflag ^= 1;
+ }
+ if (prefixes & PREFIX_ADDR)
+ {
+ aflag ^= 1;
+ }
- set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+ /* now check op code */
+ opcode = (uint32_t) tmpu8;
+reswitch:
+ switch (opcode)
+ {
+ case 0x0f:
+ if (target_read_memory (i386_record_pc, &tmpu8, 1))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc++;
+ opcode = (uint16_t) tmpu8 | 0x0f00;
+ goto reswitch;
+ break;
- /* Call dummy code. */
- set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+ /* arith & logic */
+ case 0x00 ... 0x05:
+ case 0x08 ... 0x0d:
+ case 0x10 ... 0x15:
+ case 0x18 ... 0x1d:
+ case 0x20 ... 0x25:
+ case 0x28 ... 0x2d:
+ case 0x30 ... 0x35:
+ case 0x38 ... 0x3d:
+ if (((opcode >> 3) & 7) != OP_CMPL)
+ {
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
- set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
- set_gdbarch_register_to_value (gdbarch, i386_register_to_value);
- set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
+ switch ((opcode >> 1) & 3)
+ {
+ /* OP Ev, Gv */
+ case 0:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ break;
+ /* OP Gv, Ev */
+ case 1:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ break;
+ /* OP A, Iv */
+ case 2:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
- set_gdbarch_return_value (gdbarch, i386_return_value);
+ /* GRP1 */
+ case 0x80 ... 0x83:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
- set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+ if (reg != OP_CMPL)
+ {
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
- /* Stack grows downward. */
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
- set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
- set_gdbarch_decr_pc_after_break (gdbarch, 1);
+ /* inv */
+ case 0x40 ... 0x47:
+ /* dec */
+ case 0x48 ... 0x4f:
+ if (record_arch_list_add_reg (opcode & 7))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
- set_gdbarch_frame_args_skip (gdbarch, 8);
+ /* GRP3 */
+ case 0xf6:
+ case 0xf7:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
- /* Wire in the MMX registers. */
+ switch (reg)
+ {
+ /* test */
+ case 0:
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ /* not */
+ case 2:
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ break;
+ /* neg */
+ case 3:
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ /* mul */
+ case 4:
+ /* imul */
+ case 5:
+ /* div */
+ case 6:
+ /* idiv */
+ case 7:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (ot != OT_BYTE)
+ {
+ if (record_arch_list_add_reg (I386_EDX_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ default:
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ break;
+ }
+ break;
+
+ /* GRP4 */
+ case 0xfe:
+ /* GRP5 */
+ case 0xff:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (reg >= 2 && opcode == 0xfe)
+ {
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+
+ switch (reg)
+ {
+ /* inc */
+ case 0:
+ /* dec */
+ case 1:
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ /* call */
+ case 2:
+ /* push */
+ case 6:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+ {
+ return (-1);
+ }
+ break;
+ /* lcall */
+ case 3:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_CS_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 2)), (1 << (dflag + 2))))
+ {
+ return (-1);
+ }
+ break;
+ /* jmp */
+ case 4:
+ /* ljmp */
+ case 5:
+ break;
+ default:
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ break;
+ }
+ break;
+
+ /* test */
+ case 0x84:
+ case 0x85:
+ case 0xa8:
+ case 0xa9:
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* CWDE/CBW */
+ case 0x98:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* CDQ/CWD */
+ case 0x99:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EDX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* imul */
+ case 0x0faf:
+ case 0x69:
+ case 0x6b:
+ ot = dflag + OT_WORD;
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* xadd */
+ case 0x0fc0:
+ case 0x0fc1:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* cmpxchg */
+ case 0x0fb0:
+ case 0x0fb1:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* cmpxchg8b */
+ case 0x0fc7:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EDX_REGNUM))
+ {
+ return (-1);
+ }
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* push */
+ case 0x50 ... 0x57:
+ case 0x68:
+ case 0x6a:
+ /* push es */
+ case 0x06:
+ /* push cs */
+ case 0x0e:
+ /* push ss */
+ case 0x16:
+ /* push ds */
+ case 0x1e:
+ /* push fs */
+ case 0x0fa0:
+ /* push gs */
+ case 0x0fa8:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+ {
+ return (-1);
+ }
+ break;
+
+ /* pop */
+ case 0x58 ... 0x5f:
+ ot = dflag + OT_WORD;
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (ot == OT_BYTE)
+ {
+ opcode &= 0x3;
+ }
+ if (record_arch_list_add_reg (opcode & 0x7))
+ {
+ return (-1);
+ }
+ break;
+
+ /* pusha */
+ case 0x60:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 4)), (1 << (dflag + 4))))
+ {
+ return (-1);
+ }
+ break;
+
+ /* popa */
+ case 0x61:
+ for (tmpu8 = I386_EAX_REGNUM; tmpu8 <= I386_EDI_REGNUM; tmpu8++)
+ {
+ if (record_arch_list_add_reg (tmpu8))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* pop */
+ case 0x8f:
+ ot = dflag + OT_WORD;
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* enter */
+ case 0xc8:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EBP_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+ {
+ return (-1);
+ }
+ break;
+
+ /* leave */
+ case 0xc9:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EBP_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* pop es */
+ case 0x07:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_ES_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* pop ss */
+ case 0x17:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_SS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* pop ds */
+ case 0x1f:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_DS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* pop fs */
+ case 0x0fa1:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_FS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* pop gs */
+ case 0x0fa9:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_GS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* mov */
+ case 0x88:
+ case 0x89:
+ case 0xc6:
+ case 0xc7:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ /* mov */
+ case 0x8a:
+ case 0x8b:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* mov seg */
+ case 0x8e:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+
+ switch (reg)
+ {
+ case 0:
+ tmpu8 = I386_ES_REGNUM;
+ break;
+ case 2:
+ tmpu8 = I386_SS_REGNUM;
+ break;
+ case 3:
+ tmpu8 = I386_DS_REGNUM;
+ break;
+ case 4:
+ tmpu8 = I386_FS_REGNUM;
+ break;
+ case 5:
+ tmpu8 = I386_GS_REGNUM;
+ break;
+ default:
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ break;
+ }
+ if (record_arch_list_add_reg (tmpu8))
+ {
+ return (-1);
+ }
+
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* mov seg */
+ case 0x8c:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (reg > 5)
+ {
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+
+ if (mod == 3)
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ ot = OT_WORD;
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* movzbS */
+ case 0x0fb6:
+ /* movzwS */
+ case 0x0fb7:
+ /* movsbS */
+ case 0x0fbe:
+ /* movswS */
+ case 0x0fbf:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ break;
+
+ /* lea */
+ case 0x8d:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+
+ ot = dflag;
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ break;
+
+ /* mov EAX */
+ case 0xa0:
+ case 0xa1:
+ /* xlat */
+ case 0xd7:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* mov EAX */
+ case 0xa2:
+ case 0xa3:
+ {
+ uint32_t addr;
+
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+ if (aflag)
+ {
+ if (target_read_memory (i386_record_pc, (gdb_byte *) & addr, 4))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc += 4;
+ }
+ else
+ {
+ if (target_read_memory (i386_record_pc, (gdb_byte *) & tmpu16, 4))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc += 2;
+ addr = tmpu16;
+ }
+ if (record_arch_list_add_mem (addr, 1 << ot))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* mov R, Ib */
+ case 0xb0 ... 0xb7:
+ if (record_arch_list_add_reg ((opcode & 0x7) & 0x3))
+ {
+ return (-1);
+ }
+ break;
+
+ /* mov R, Iv */
+ case 0xb8 ... 0xbf:
+ if (record_arch_list_add_reg (opcode & 0x7))
+ {
+ return (-1);
+ }
+ break;
+
+ /* xchg R, EAX */
+ case 0x91 ... 0x97:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (opcode & 0x7))
+ {
+ return (-1);
+ }
+ break;
+
+ /* xchg Ev, Gv */
+ case 0x86:
+ case 0x87:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+
+ if (mod == 3)
+ {
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+
+ if (ot == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ break;
+
+ /* les Gv */
+ case 0xc4:
+ /* lds Gv */
+ case 0xc5:
+ /* lss Gv */
+ case 0x0fb2:
+ /* lfs Gv */
+ case 0x0fb4:
+ /* lgs Gv */
+ case 0x0fb5:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ if (opcode > 0xff)
+ {
+ i386_record_pc -= 3;
+ }
+ else
+ {
+ i386_record_pc -= 2;
+ }
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+
+ switch (opcode)
+ {
+ /* les Gv */
+ case 0xc4:
+ tmpu8 = I386_ES_REGNUM;
+ break;
+ /* lds Gv */
+ case 0xc5:
+ tmpu8 = I386_DS_REGNUM;
+ break;
+ /* lss Gv */
+ case 0x0fb2:
+ tmpu8 = I386_SS_REGNUM;
+ break;
+ /* lfs Gv */
+ case 0x0fb4:
+ tmpu8 = I386_FS_REGNUM;
+ break;
+ /* lgs Gv */
+ case 0x0fb5:
+ tmpu8 = I386_GS_REGNUM;
+ break;
+ }
+ if (record_arch_list_add_reg (tmpu8))
+ {
+ return (-1);
+ }
+
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ break;
+
+ /* shifts */
+ case 0xc0:
+ case 0xc1:
+ case 0xd0:
+ case 0xd1:
+ case 0xd2:
+ case 0xd3:
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+
+ if (mod != 3 && (opcode == 0xd2 || opcode == 0xd3))
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (ot == OT_BYTE)
+ {
+ rm &= 0x3;
+ }
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ case 0x0fa4:
+ case 0x0fa5:
+ case 0x0fac:
+ case 0x0fad:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* floats */
+ /* XXX */
+
+ /* string ops */
+ /* movsS */
+ case 0xa4:
+ case 0xa5:
+ /* stosS */
+ case 0xaa:
+ case 0xab:
+ /* insS */
+ case 0x6c:
+ case 0x6d:
+ {
+ uint32_t addr;
+
+ if ((opcode & 1) == 0)
+ {
+ ot = OT_BYTE;
+ }
+ else
+ {
+ ot = dflag + OT_WORD;
+ }
+ if (opcode == 0xa4 || opcode == 0xa5)
+ {
+ if (record_arch_list_add_reg (I386_ESI_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EDI_REGNUM))
+ {
+ return (-1);
+ }
+
+ regcache_raw_read (record_regcache, I386_EDI_REGNUM,
+ (gdb_byte *) & addr);
+ if (!aflag)
+ {
+ addr &= 0xffff;
+ /* addr += ((uint32_t)read_register (I386_ES_REGNUM)) << 4; */
+ printf_unfiltered (_
+ ("record: cann't get the value of the segment register.\n"));
+ return (-1);
+ }
+
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+ {
+ uint32_t count;
+
+ regcache_raw_read (record_regcache, I386_ECX_REGNUM,
+ (gdb_byte *) & count);
+ if (!aflag)
+ {
+ count &= 0xffff;
+ }
+
+ regcache_raw_read (record_regcache, I386_EFLAGS_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if ((tmpu32 >> 10) & 0x1)
+ {
+ addr -= (count - 1) * (1 << ot);
+ }
+
+ if (record_arch_list_add_mem (addr, count * (1 << ot)))
+ {
+ return (-1);
+ }
+
+ if (record_arch_list_add_reg (I386_ECX_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (record_arch_list_add_mem (addr, 1 << ot))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+
+ /* lodsS */
+ case 0xac:
+ case 0xad:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_ESI_REGNUM))
+ {
+ return (-1);
+ }
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+ {
+ if (record_arch_list_add_reg (I386_ECX_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* outsS */
+ case 0x6e:
+ case 0x6f:
+ if (record_arch_list_add_reg (I386_ESI_REGNUM))
+ {
+ return (-1);
+ }
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+ {
+ if (record_arch_list_add_reg (I386_ECX_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* scasS */
+ case 0xae:
+ case 0xaf:
+ if (record_arch_list_add_reg (I386_EDI_REGNUM))
+ {
+ return (-1);
+ }
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+ {
+ if (record_arch_list_add_reg (I386_ECX_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* cmpsS */
+ case 0xa6:
+ case 0xa7:
+ if (record_arch_list_add_reg (I386_EDI_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_ESI_REGNUM))
+ {
+ return (-1);
+ }
+ if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))
+ {
+ if (record_arch_list_add_reg (I386_ECX_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* port I/O */
+ case 0xe4:
+ case 0xe5:
+ case 0xec:
+ case 0xed:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ case 0xe6:
+ case 0xe7:
+ case 0xee:
+ case 0xef:
+ break;
+
+ /* control */
+ /* ret im */
+ case 0xc2:
+ /* ret */
+ case 0xc3:
+ /* lret im */
+ case 0xca:
+ /* lret */
+ case 0xcb:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_CS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* iret */
+ case 0xcf:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_CS_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* call im */
+ case 0xe8:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+ {
+ return (-1);
+ }
+ break;
+
+ /* lcall im */
+ case 0x9a:
+ if (record_arch_list_add_reg (I386_CS_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 2)), (1 << (dflag + 2))))
+ {
+ return (-1);
+ }
+ break;
+
+ /* jmp im */
+ case 0xe9:
+ /* ljmp im */
+ case 0xea:
+ /* jmp Jb */
+ case 0xeb:
+ /* jcc Jb */
+ case 0x70 ... 0x7f:
+ /* jcc Jv */
+ case 0x0f80 ... 0x0f8f:
+ break;
+
+ /* setcc Gv */
+ case 0x0f90 ... 0x0f9f:
+ ot = OT_BYTE;
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod == 3)
+ {
+ if (record_arch_list_add_reg (rm & 0x3))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* cmov Gv, Ev */
+ case 0x0f40 ... 0x0f4f:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (dflag == OT_BYTE)
+ {
+ reg &= 0x3;
+ }
+ if (record_arch_list_add_reg (reg & 0x3))
+ {
+ return (-1);
+ }
+ break;
+
+ /* flags */
+ /* pushf */
+ case 0x9c:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, I386_ESP_REGNUM,
+ (gdb_byte *) & tmpu32);
+ if (record_arch_list_add_mem
+ ((CORE_ADDR) tmpu32 - (1 << (dflag + 1)), (1 << (dflag + 1))))
+ {
+ return (-1);
+ }
+ break;
+
+ /* popf */
+ case 0x9d:
+ if (record_arch_list_add_reg (I386_ESP_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* sahf */
+ case 0x9e:
+ /* cmc */
+ case 0xf5:
+ /* clc */
+ case 0xf8:
+ /* stc */
+ case 0xf9:
+ /* cld */
+ case 0xfc:
+ /* std */
+ case 0xfd:
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* lahf */
+ case 0x9f:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* bit operations */
+ /* bt/bts/btr/btc Gv, im */
+ case 0x0fba:
+ /* bts */
+ case 0x0fab:
+ /* btr */
+ case 0x0fb3:
+ /* btc */
+ case 0x0fbb:
+ ot = dflag + OT_WORD;
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (reg < 4)
+ {
+ i386_record_pc -= 3;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+ reg -= 4;
+ if (reg != 0)
+ {
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* bt Gv, Ev */
+ case 0x0fa3:
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* bsf */
+ case 0x0fbc:
+ /* bsr */
+ case 0x0fbd:
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* bcd */
+ /* daa */
+ case 0x27:
+ /* das */
+ case 0x2f:
+ /* aaa */
+ case 0x37:
+ /* aas */
+ case 0x3f:
+ /* aam */
+ case 0xd4:
+ /* aad */
+ case 0xd5:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* misc */
+ /* nop */
+ case 0x90:
+ if (prefixes & PREFIX_LOCK)
+ {
+ i386_record_pc -= 1;
+ goto no_support;
+ }
+ break;
+
+ /* fwait */
+ /* XXX */
+ case 0x9b:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction fwait.\n"));
+ i386_record_pc -= 1;
+ goto no_support;
+ break;
+
+ /* int3 */
+ /* XXX */
+ case 0xcc:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction int3.\n"));
+ i386_record_pc -= 1;
+ goto no_support;
+ break;
+
+ /* int */
+ /* XXX */
+ case 0xcd:
+ {
+ int ret;
+ if (target_read_memory (i386_record_pc, &tmpu8, 1))
+ {
+ printf_unfiltered (_("record: read memeory 0x%s error.\n"),
+ paddr_nz (i386_record_pc));
+ return (-1);
+ }
+ i386_record_pc++;
+ if (tmpu8 != 0x80
+ || gdbarch_tdep (gdbarch)->i386_intx80_record == NULL)
+ {
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction int 0x%02x.\n"),
+ tmpu8);
+ i386_record_pc -= 2;
+ goto no_support;
+ }
+ ret = gdbarch_tdep (gdbarch)->i386_intx80_record ();
+ if (ret)
+ {
+ return (ret);
+ }
+ }
+ break;
+
+ /* into */
+ /* XXX */
+ case 0xce:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction into.\n"));
+ i386_record_pc -= 1;
+ goto no_support;
+ break;
+
+ /* cli */
+ case 0xfa:
+ /* sti */
+ case 0xfb:
+ break;
+
+ /* bound */
+ case 0x62:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction bound.\n"));
+ i386_record_pc -= 1;
+ goto no_support;
+ break;
+
+ /* bswap reg */
+ case 0x0fc8 ... 0x0fcf:
+ if (record_arch_list_add_reg (opcode & 7))
+ {
+ return (-1);
+ }
+ break;
+
+ /* salc */
+ case 0xd6:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* loopnz */
+ case 0xe0:
+ /* loopz */
+ case 0xe1:
+ /* loop */
+ case 0xe2:
+ /* jecxz */
+ case 0xe3:
+ if (record_arch_list_add_reg (I386_ECX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* wrmsr */
+ case 0x0f30:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction wrmsr.\n"));
+ i386_record_pc -= 2;
+ goto no_support;
+ break;
+
+ /* rdmsr */
+ case 0x0f32:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction rdmsr.\n"));
+ i386_record_pc -= 2;
+ goto no_support;
+ break;
+
+ /* rdtsc */
+ case 0x0f31:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction rdtsc.\n"));
+ i386_record_pc -= 2;
+ goto no_support;
+ break;
+
+ /* sysenter */
+ case 0x0f34:
+ {
+ int ret;
+ if (gdbarch_tdep (gdbarch)->i386_sysenter_record == NULL)
+ {
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction sysenter.\n"));
+ i386_record_pc -= 2;
+ goto no_support;
+ }
+ ret = gdbarch_tdep (gdbarch)->i386_sysenter_record ();
+ if (ret)
+ {
+ return (ret);
+ }
+ }
+ break;
+
+ /* sysexit */
+ case 0x0f35:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction sysexit.\n"));
+ i386_record_pc -= 2;
+ goto no_support;
+ break;
+
+ /* cpuid */
+ case 0x0fa2:
+ if (record_arch_list_add_reg (I386_EAX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_ECX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EDX_REGNUM))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EBX_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* hlt */
+ case 0xf4:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction hlt.\n"));
+ i386_record_pc -= 1;
+ goto no_support;
+ break;
+
+ case 0x0f00:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ switch (reg)
+ {
+ /* sldt */
+ case 0:
+ /* str */
+ case 1:
+ if (mod == 3)
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ ot = OT_WORD;
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ break;
+ /* lldt */
+ case 2:
+ /* ltr */
+ case 3:
+ break;
+ /* verr */
+ case 4:
+ /* verw */
+ case 5:
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ default:
+ i386_record_pc -= 3;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ break;
+ }
+ break;
+
+ case 0x0f01:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ switch (reg)
+ {
+ /* sgdt */
+ case 0:
+ {
+ uint32_t addr;
+
+ if (mod == 3)
+ {
+ i386_record_pc -= 3;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+
+ if (override)
+ {
+ printf_unfiltered (_
+ ("record: cann't get the value of the segment register in address 0x%s. Record ignore this change.\n"),
+ paddr_nz (read_pc ()));
+ }
+ else
+ {
+ if (i386_record_lea_modrm_addr (&addr))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (addr, 2))
+ {
+ return (-1);
+ }
+ addr += 2;
+ if (record_arch_list_add_mem (addr, 4))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+ case 1:
+ if (mod == 3)
+ {
+ switch (rm)
+ {
+ /* monitor */
+ case 0:
+ break;
+ /* mwait */
+ case 1:
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+ default:
+ i386_record_pc -= 3;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ break;
+ }
+ }
+ else
+ {
+ /* sidt */
+ if (override)
+ {
+ printf_unfiltered (_
+ ("record: cann't get the value of the segment register in address 0x%s. Record ignore this change.\n"),
+ paddr_nz (read_pc ()));
+ }
+ else
+ {
+ uint32_t addr;
+
+ if (i386_record_lea_modrm_addr (&addr))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_mem (addr, 2))
+ {
+ return (-1);
+ }
+ addr += 2;
+ if (record_arch_list_add_mem (addr, 4))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+ /* lgdt */
+ case 2:
+ /* lidt */
+ case 3:
+ /* invlpg */
+ case 7:
+ default:
+ if (mod == 3)
+ {
+ i386_record_pc -= 3;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+ break;
+ /* smsw */
+ case 4:
+ if (mod == 3)
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ ot = OT_WORD;
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ break;
+ /* lmsw */
+ case 6:
+ break;
+ }
+ break;
+
+ /* invd */
+ case 0x0f08:
+ /* wbinvd */
+ case 0x0f09:
+ break;
+
+ /* arpl */
+ case 0x63:
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (mod != 3)
+ {
+ if (i386_record_lea_modrm ())
+ {
+ return (-1);
+ }
+ }
+ else
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ /* lar */
+ case 0x0f02:
+ /* lsl */
+ case 0x0f03:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (reg))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (I386_EFLAGS_REGNUM))
+ {
+ return (-1);
+ }
+ break;
+
+ case 0x0f18:
+ break;
+
+ /* nop (multi byte) */
+ case 0x0f19 ... 0x0f1f:
+ break;
+
+ /* mov reg, crN */
+ case 0x0f20:
+ /* mov crN, reg */
+ case 0x0f22:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if ((modrm & 0xc0) != 0xc0)
+ {
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+ switch (reg)
+ {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ case 8:
+ if (opcode & 2)
+ {
+ }
+ else
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ break;
+ default:
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ break;
+ }
+ break;
+
+ /* mov reg, drN */
+ case 0x0f21:
+ /* mov drN, reg */
+ case 0x0f23:
+ if (i386_record_modrm ())
+ {
+ return (-1);
+ }
+ if ((modrm & 0xc0) != 0xc0 || reg == 4 || reg == 5 || reg >= 8)
+ {
+ i386_record_pc -= 2;
+ opcode = opcode << 8 | modrm;
+ goto no_support;
+ }
+ if (opcode & 2)
+ {
+ }
+ else
+ {
+ if (record_arch_list_add_reg (rm))
+ {
+ return (-1);
+ }
+ }
+ break;
+
+ /* clts */
+ case 0x0f06:
+ break;
+
+ /* MMX/SSE/SSE2/PNI support */
+ /* XXX */
+
+ default:
+ if (opcode > 0xff)
+ {
+ i386_record_pc -= 2;
+ }
+ else
+ {
+ i386_record_pc -= 1;
+ }
+ goto no_support;
+ break;
+ }
+
+ if (!need_dasm)
+ {
+ if (record_arch_list_add_reg (I386_EIP_REGNUM))
+ {
+ return (-1);
+ }
+ }
+ if (record_arch_list_add_end (need_dasm))
+ {
+ return (-1);
+ }
+
+ return (0);
+
+no_support:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support instruction 0x%02x at address 0x%s.\n"),
+ (unsigned int) (opcode), paddr_nz (i386_record_pc));
+ return (-1);
+}
+
+\f
+static struct gdbarch *
+i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep;
+ struct gdbarch *gdbarch;
+
+ /* If there is already a candidate, use it. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+ /* Allocate space for the new architecture. */
+ tdep = XCALLOC (1, struct gdbarch_tdep);
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* General-purpose registers. */
+ tdep->gregset = NULL;
+ tdep->gregset_reg_offset = NULL;
+ tdep->gregset_num_regs = I386_NUM_GREGS;
+ tdep->sizeof_gregset = 0;
+
+ /* Floating-point registers. */
+ tdep->fpregset = NULL;
+ tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+
+ /* The default settings include the FPU registers, the MMX registers
+ and the SSE registers. This can be overridden for a specific ABI
+ by adjusting the members `st0_regnum', `mm0_regnum' and
+ `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
+ will show up in the output of "info all-registers". Ideally we
+ should try to autodetect whether they are available, such that we
+ can prevent "info all-registers" from displaying registers that
+ aren't available.
+
+ NOTE: kevinb/2003-07-13: ... if it's a choice between printing
+ [the SSE registers] always (even when they don't exist) or never
+ showing them to the user (even when they do exist), I prefer the
+ former over the latter. */
+
+ tdep->st0_regnum = I386_ST0_REGNUM;
+
+ /* The MMX registers are implemented as pseudo-registers. Put off
+ calculating the register number for %mm0 until we know the number
+ of raw registers. */
+ tdep->mm0_regnum = 0;
+
+ /* I386_NUM_XREGS includes %mxcsr, so substract one. */
+ tdep->num_xmm_regs = I386_NUM_XREGS - 1;
+
+ tdep->jb_pc_offset = -1;
+ tdep->struct_return = pcc_struct_return;
+ tdep->sigtramp_start = 0;
+ tdep->sigtramp_end = 0;
+ tdep->sigtramp_p = i386_sigtramp_p;
+ tdep->sigcontext_addr = NULL;
+ tdep->sc_reg_offset = NULL;
+ tdep->sc_pc_offset = -1;
+ tdep->sc_sp_offset = -1;
+
+ /* The format used for `long double' on almost all i386 targets is
+ the i387 extended floating-point format. In fact, of all targets
+ in the GCC 2.95 tree, only OSF/1 does it different, and insists
+ on having a `long double' that's not `long' at all. */
+ set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext);
+
+ /* Although the i387 extended floating-point has only 80 significant
+ bits, a `long double' actually takes up 96, probably to enforce
+ alignment. */
+ set_gdbarch_long_double_bit (gdbarch, 96);
+
+ /* The default ABI includes general-purpose registers,
+ floating-point registers, and the SSE registers. */
+ set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
+ set_gdbarch_register_name (gdbarch, i386_register_name);
+ set_gdbarch_register_type (gdbarch, i386_register_type);
+
+ /* Register numbers of various important registers. */
+ set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
+ set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
+ set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
+ set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+
+ /* NOTE: kettenis/20040418: GCC does have two possible register
+ numbering schemes on the i386: dbx and SVR4. These schemes
+ differ in how they number %ebp, %esp, %eflags, and the
+ floating-point registers, and are implemented by the arrays
+ dbx_register_map[] and svr4_dbx_register_map in
+ gcc/config/i386.c. GCC also defines a third numbering scheme in
+ gcc/config/i386.c, which it designates as the "default" register
+ map used in 64bit mode. This last register numbering scheme is
+ implemented in dbx64_register_map, and is used for AMD64; see
+ amd64-tdep.c.
+
+ Currently, each GCC i386 target always uses the same register
+ numbering scheme across all its supported debugging formats
+ i.e. SDB (COFF), stabs and DWARF 2. This is because
+ gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
+ DBX_REGISTER_NUMBER macro which is defined by each target's
+ respective config header in a manner independent of the requested
+ output debugging format.
+
+ This does not match the arrangement below, which presumes that
+ the SDB and stabs numbering schemes differ from the DWARF and
+ DWARF 2 ones. The reason for this arrangement is that it is
+ likely to get the numbering scheme for the target's
+ default/native debug format right. For targets where GCC is the
+ native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
+ targets where the native toolchain uses a different numbering
+ scheme for a particular debug format (stabs-in-ELF on Solaris)
+ the defaults below will have to be overridden, like
+ i386_elf_init_abi() does. */
+
+ /* Use the dbx register numbering scheme for stabs and COFF. */
+ set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+ set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
+
+ /* Use the SVR4 register numbering scheme for DWARF and DWARF 2. */
+ set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+
+ /* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
+ be in use on any of the supported i386 targets. */
+
+ set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
+
+ set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
+
+ /* Call dummy code. */
+ set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
+
+ set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
+ set_gdbarch_register_to_value (gdbarch, i386_register_to_value);
+ set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
+
+ set_gdbarch_return_value (gdbarch, i386_return_value);
+
+ set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+
+ /* Stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
+ set_gdbarch_decr_pc_after_break (gdbarch, 1);
+
+ set_gdbarch_frame_args_skip (gdbarch, 8);
+
+ /* Wire in the MMX registers. */
set_gdbarch_num_pseudo_regs (gdbarch, i386_num_mmx_regs);
set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
@@ -2503,6 +5034,8 @@ i386_gdbarch_init (struct gdbarch_info i
if (tdep->mm0_regnum == 0)
tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
+ set_gdbarch_record (gdbarch, i386_record);
+
return gdbarch;
}
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -106,6 +106,9 @@ struct gdbarch_tdep
/* ISA-specific data types. */
struct type *i386_mmx_type;
struct type *i386_sse_type;
+
+ int (*i386_intx80_record) (void);
+ int (*i386_sysenter_record) (void);
};
/* Floating-point registers. */
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -49,6 +49,8 @@
#include "target-descriptions.h"
#include "user-regs.h"
+#include "record.h"
+
/* Functions exported for general use, in inferior.h: */
void all_registers_info (char *, int);
@@ -189,6 +191,12 @@ CORE_ADDR step_range_end; /* Exclusive *
struct frame_id step_frame_id;
+/* Prev stack frame address of "step_frame_id".
+ When GDB is in the reverse debug mode, it is used to make sure if inferior return to
+ the prev function. */
+
+struct frame_id step_prev_frame_id;
+
enum step_over_calls_kind step_over_calls;
/* If stepping, nonzero means step count is > 1
@@ -738,6 +746,19 @@ step_1 (int skip_subroutines, int single
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
+ if (gdb_is_reverse)
+ {
+ frame = get_prev_frame (frame);
+ if (frame)
+ {
+ step_prev_frame_id = get_frame_id (frame);
+ }
+ else
+ {
+ step_prev_frame_id = null_frame_id;
+ }
+ }
+
if (!single_inst)
{
find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
@@ -837,6 +858,19 @@ step_once (int skip_subroutines, int sin
error (_("No current frame"));
step_frame_id = get_frame_id (frame);
+ if (gdb_is_reverse)
+ {
+ frame = get_prev_frame (frame);
+ if (frame)
+ {
+ step_prev_frame_id = get_frame_id (frame);
+ }
+ else
+ {
+ step_prev_frame_id = null_frame_id;
+ }
+ }
+
if (!single_inst)
{
find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end);
@@ -1089,6 +1123,19 @@ until_next_command (int from_tty)
step_over_calls = STEP_OVER_ALL;
step_frame_id = get_frame_id (frame);
+ if (gdb_is_reverse)
+ {
+ frame = get_prev_frame (frame);
+ if (frame)
+ {
+ step_prev_frame_id = get_frame_id (frame);
+ }
+ else
+ {
+ step_prev_frame_id = null_frame_id;
+ }
+ }
+
step_multi = 0; /* Only one call to proceed */
proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1);
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -318,6 +318,12 @@ extern CORE_ADDR step_range_end; /* Excl
extern struct frame_id step_frame_id;
+/* Prev stack frame address of "step_frame_id".
+ When GDB is in the reverse debug mode, it is used to make sure if inferior return to
+ the prev function. */
+
+extern struct frame_id step_prev_frame_id;
+
/* 1 means step over all subroutine calls.
-1 means step over calls to undebuggable functions. */
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -49,6 +49,12 @@
#include "gdb_assert.h"
#include "mi/mi-common.h"
+#include "record.h"
+
+/* When the record function want inferior step before call "keep_going",
+ "record_resume_step" will be set to 1. After that, it will be set back to 0. */
+static int record_resume_step = 0;
+
/* Prototypes for local functions */
static void signals_info (char *, int);
@@ -518,6 +524,21 @@ resume (int step, enum target_signal sig
fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%d, signal=%d)\n",
step, sig);
+ if (gdb_is_recording)
+ {
+ if (record_list && (record_list->next || gdb_is_reverse))
+ {
+ discard_cleanups (old_cleanups);
+ record_wait_step = step;
+ return;
+ }
+ else
+ {
+ step = 1;
+ record_message (current_gdbarch);
+ }
+ }
+
/* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
@@ -1026,10 +1047,18 @@ wait_for_inferior (int treat_exec_as_sig
while (1)
{
- if (deprecated_target_wait_hook)
- ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
+ if (record_list && (record_list->next || gdb_is_reverse))
+ {
+ ecs->ptid = record_wait (current_gdbarch, ecs->waiton_ptid, ecs->wp);
+ }
else
- ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+ {
+ if (deprecated_target_wait_hook)
+ ecs->ptid =
+ deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
+ else
+ ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+ }
if (treat_exec_as_sigtrap && ecs->ws.kind == TARGET_WAITKIND_EXECD)
{
@@ -2004,10 +2033,19 @@ handle_inferior_event (struct execution_
SPARC. */
if (stop_signal == TARGET_SIGNAL_TRAP)
- ecs->random_signal
- = !(bpstat_explains_signal (stop_bpstat)
- || stepping_over_breakpoint
- || (step_range_end && step_resume_breakpoint == NULL));
+ {
+ if (gdb_is_reverse || gdb_is_recording)
+ {
+ ecs->random_signal = 0;
+ }
+ else
+ {
+ ecs->random_signal
+ = !(bpstat_explains_signal (stop_bpstat)
+ || stepping_over_breakpoint
+ || (step_range_end && step_resume_breakpoint == NULL));
+ }
+ }
else
{
ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
@@ -2489,6 +2527,15 @@ process_event_stop_test:
/* We're doing a "next", set a breakpoint at callee's return
address (the address at which the caller will
resume). */
+
+ if (gdb_is_reverse || gdb_is_recording)
+ {
+ record_resume_step = 1;
+ keep_going (ecs);
+ record_resume_step = 0;
+ return;
+ }
+
insert_step_resume_breakpoint_at_caller (get_current_frame ());
keep_going (ecs);
return;
@@ -2551,6 +2598,15 @@ process_event_stop_test:
return;
}
+ if ((gdb_is_reverse || gdb_is_recording)
+ && step_over_calls == STEP_OVER_UNDEBUGGABLE)
+ {
+ record_resume_step = 1;
+ keep_going (ecs);
+ record_resume_step = 0;
+ return;
+ }
+
/* Set a breakpoint at callee's return address (the address at
which the caller will resume). */
insert_step_resume_breakpoint_at_caller (get_current_frame ());
@@ -2605,6 +2661,14 @@ process_event_stop_test:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepped into undebuggable function\n");
+ if (gdb_is_reverse || gdb_is_recording)
+ {
+ record_resume_step = 1;
+ keep_going (ecs);
+ record_resume_step = 0;
+ return;
+ }
+
/* The inferior just stepped into, or returned to, an
undebuggable function (where there is no debugging information
and no line number corresponding to the address where the
@@ -2654,15 +2718,58 @@ process_event_stop_test:
or can this happen as a result of a return or longjmp?). */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: no line number info\n");
+
+ if ((step_over_calls == STEP_OVER_ALL && gdb_is_reverse)
+ || gdb_is_recording)
+ {
+ record_resume_step = 1;
+ keep_going (ecs);
+ record_resume_step = 0;
+ return;
+ }
+
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
return;
}
- if ((stop_pc == ecs->sal.pc)
- && (ecs->current_line != ecs->sal.line
- || ecs->current_symtab != ecs->sal.symtab))
+ if (gdb_is_reverse
+ && frame_id_eq (get_frame_id (get_current_frame ()),
+ step_prev_frame_id))
+ {
+ if (debug_infrun)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: return to the prev function\n");
+ }
+ stop_step = 1;
+ print_stop_reason (END_STEPPING_RANGE, 0);
+ stop_stepping (ecs);
+ return;
+ }
+
+ if (!frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id)
+ && (gdb_is_reverse || gdb_is_recording))
+ {
+ if ((stop_pc != ecs->sal.pc && gdb_is_reverse)
+ || (step_over_calls == STEP_OVER_ALL && gdb_is_recording))
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: maybe stepped into subroutine\n");
+ record_resume_step = 1;
+ keep_going (ecs);
+ record_resume_step = 0;
+ return;
+ }
+ }
+
+ if (((stop_pc == ecs->sal.pc && !gdb_is_reverse)
+ || (stop_pc >= ecs->sal.pc && stop_pc < ecs->sal.end
+ && gdb_is_reverse)) && (ecs->current_line != ecs->sal.line
+ || ecs->current_symtab !=
+ ecs->sal.symtab))
{
/* We are at the start of a different line. So stop. Note that
we don't stop if we step into the middle of a different line.
@@ -2670,6 +2777,7 @@ process_event_stop_test:
better. */
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different line\n");
+
stop_step = 1;
print_stop_reason (END_STEPPING_RANGE, 0);
stop_stepping (ecs);
@@ -2730,7 +2838,7 @@ currently_stepping (struct execution_con
&& ((step_range_end && step_resume_breakpoint == NULL)
|| stepping_over_breakpoint))
|| ecs->stepping_through_solib_after_catch
- || bpstat_should_step ());
+ || bpstat_should_step () || record_resume_step);
}
/* Subroutine call with source code we should not step over. Do step
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -633,7 +633,8 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
user-regs.c \
valarith.c valops.c valprint.c value.c varobj.c vec.c \
wrapper.c \
- xml-tdesc.c xml-support.c
+ xml-tdesc.c xml-support.c \
+ record.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -1072,7 +1073,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
tramp-frame.o \
solib.o solib-null.o \
prologue-value.o memory-map.o xml-support.o \
- target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o
+ target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
+ record.o
TSOBS = inflow.o
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -58,6 +58,9 @@
#include "dwarf2-frame.h"
#include "user-regs.h"
+#include "record.h"
+#include <stdint.h>
+
static const struct objfile_data *mips_pdr_data;
static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum);
@@ -5213,6 +5216,734 @@ value_of_mips_user_reg (struct frame_inf
return value_of_register (*reg_p, frame);
}
+/* When "record_delay_slot" is true (mean that the prev instruction has delay
+ slot), GDB need to deal with instrction in the delay slot that address is
+ "mips_delay_slot_addr" and the instruction in target of delay slot
+ instruction that address is "mips_target_addr". */
+static CORE_ADDR mips_delay_slot_addr;
+static CORE_ADDR mips_target_addr;
+
+/* Record the value of the memory that willbe changed in current 32 bits instruction
+ to "record_arch_list".
+ Return -1 if something wrong. */
+static int
+mips_record_32 (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ uint32_t insn = (uint32_t) mips_fetch_instruction (pc);
+ uint32_t opcode;
+ const struct mips_regnum *regnum = mips_regnum (gdbarch);
+ int add_pc = 1;
+ uint32_t tmpu32;
+
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: mips_record_32 insn = 0x%08x\n",
+ (unsigned int) insn);
+ }
+
+ opcode = insn >> 26;
+ switch (opcode)
+ {
+ case 0x00:
+ switch ((insn >> 0) & 0x3f)
+ {
+ /* sll */
+ case 0x00:
+ /* srl */
+ case 0x02:
+ /* sra */
+ case 0x03:
+ /* sllv */
+ case 0x04:
+ /* srlv */
+ case 0x06:
+ /* srav */
+ case 0x07:
+ /* movz */
+ case 0x0a:
+ /* movn */
+ case 0x0b:
+ /* mfhi */
+ case 0x10:
+ /* mflo */
+ case 0x12:
+ /* add */
+ case 0x20:
+ /* addu */
+ case 0x21:
+ /* sub */
+ case 0x22:
+ /* subu */
+ case 0x23:
+ /* and */
+ case 0x24:
+ /* or */
+ case 0x25:
+ /* xor */
+ case 0x26:
+ /* nor */
+ case 0x27:
+ /* slt */
+ case 0x2a:
+ /* sltu */
+ case 0x2b:
+ goto set_rd;
+ break;
+ /* jr */
+ case 0x08:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & mips_target_addr);
+ goto set_delay_slot_pc;
+ break;
+ /* jalr */
+ case 0x09:
+ {
+ uint32_t rd = (insn >> 11) & 0x1f;
+ if (rd != 0)
+ {
+ if (record_arch_list_add_reg (rd))
+ {
+ return (-1);
+ }
+ }
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & mips_target_addr);
+ goto set_delay_slot_pc;
+ }
+ break;
+ /* sync */
+ case 0x0f:
+ break;
+ /* mthi */
+ case 0x11:
+ if (record_arch_list_add_reg (regnum->hi))
+ {
+ return (-1);
+ }
+ break;
+ /* mtlo */
+ case 0x13:
+ if (record_arch_list_add_reg (regnum->lo))
+ {
+ return (-1);
+ }
+ break;
+ /* mult */
+ case 0x18:
+ /* multu */
+ case 0x19:
+ /* div */
+ case 0x1a:
+ /* divu */
+ case 0x1b:
+ goto set_hi_lo;
+ break;
+ default:
+ goto no_support;
+ break;
+ }
+ break;
+
+ case 0x01:
+ switch ((insn >> 16) & 0x1f)
+ {
+ /* bltz */
+ case 0x00:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 < 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ break;
+ /* bgez */
+ case 0x01:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 >= 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ break;
+ /* bltzl */
+ case 0x02:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 < 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ break;
+ /* bgezl */
+ case 0x03:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 >= 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ break;
+ /* bltzal */
+ case 0x10:
+ if (record_arch_list_add_reg (31))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 < 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ break;
+ /* bgezal */
+ case 0x11:
+ if (record_arch_list_add_reg (31))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 >= 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ break;
+ /* bltzall */
+ case 0x12:
+ if (record_arch_list_add_reg (31))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 < 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ break;
+ /* bgezall */
+ case 0x13:
+ if (record_arch_list_add_reg (31))
+ {
+ return (-1);
+ }
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 >= 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ break;
+ default:
+ goto no_support;
+ break;
+ }
+ break;
+
+ /* j */
+ case 0x02:
+ mips_target_addr =
+ (pc & 0xf0000000) | (((insn >> 0) & 0x03ffffff) << 2);
+ goto set_delay_slot_pc;
+ break;
+
+ /* beq */
+ case 0x04:
+ {
+ uint32_t tmp;
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+ (gdb_byte *) & tmp);
+ if (tmpu32 == tmp)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ }
+ break;
+
+ /* bne */
+ case 0x05:
+ {
+ uint32_t tmp;
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+ (gdb_byte *) & tmp);
+ if (tmpu32 != tmp)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ }
+ break;
+
+ /* blez */
+ case 0x06:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 <= 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ break;
+
+ /* bgtz */
+ case 0x07:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 > 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ break;
+
+ /* beql */
+ case 0x14:
+ {
+ uint32_t tmp;
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+ (gdb_byte *) & tmp);
+ if (tmpu32 == tmp)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ }
+ break;
+
+ /* bnel */
+ case 0x15:
+ {
+ uint32_t tmp;
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ regcache_raw_read (record_regcache, (insn >> 16) & 0x1f),
+ (gdb_byte *) & tmp);
+ if (tmpu32 == tmp)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ }
+ break;
+
+ /* blezl */
+ case 0x16:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 <= 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ break;
+
+ /* bgtzl */
+ case 0x17:
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f),
+ (gdb_byte *) & tmpu32);
+ if (tmpu32 > 0)
+ {
+ goto set_imm_delay_slot_pc;
+ }
+ else
+ {
+ goto set_pc;
+ }
+ break;
+
+ /* jal */
+ case 0x03:
+ if (record_arch_list_add_reg (31))
+ {
+ return (-1);
+ }
+ mips_target_addr =
+ (pc & 0xf0000000) | (((insn >> 0) & 0x03ffffff) << 2);
+ goto set_delay_slot_pc;
+ break;
+
+ /* jalx */
+ case 0x1d:
+ goto no_support;
+ break;
+
+ /* addi */
+ case 0x08:
+ /* addiu */
+ case 0x09:
+ /* slti */
+ case 0x0a:
+ /* sltiu */
+ case 0x0b:
+ /* andi */
+ case 0x0c:
+ /* ori */
+ case 0x0d:
+ /* xori */
+ case 0x0e:
+ /* lui */
+ case 0x0f:
+ goto set_rt;
+ break;
+
+ /* COP0 */
+ case 0x10:
+ if ((insn >> 25) & 0x1)
+ {
+ switch ((insn >> 0) & 0x3f)
+ {
+ /* eret */
+ case 0x18:
+ goto set_pc;
+ break;
+ default:
+ goto no_support;
+ break;
+ }
+ }
+ else
+ {
+ switch ((insn >> 21) & 0x1f)
+ {
+ /* mfc0 */
+ case 0x00:
+ goto set_rt;
+ break;
+ /* mtc0 */
+ case 0x04:
+ {
+ switch ((insn >> 11) & 0x1f)
+ {
+ case 13:
+ /* Cause */
+ if (record_arch_list_add_reg (regnum->cause))
+ {
+ return (-1);
+ }
+ case 8:
+ /* badvaddr */
+ if (record_arch_list_add_reg (regnum->badvaddr))
+ {
+ return (-1);
+ }
+ }
+ }
+ break;
+ default:
+ goto no_support;
+ break;
+ }
+ }
+ break;
+
+ case 0x1c:
+ switch ((insn >> 0) & 0x3f)
+ {
+ /* madd */
+ case 0x00:
+ /* maddu */
+ case 0x01:
+ /* msub */
+ case 0x04:
+ /* msubu */
+ case 0x05:
+ goto set_hi_lo;
+ break;
+ /* mul */
+ case 0x02:
+ {
+ uint32_t rd = (insn >> 11) & 0x1f;
+ if (rd != 0)
+ {
+ if (record_arch_list_add_reg (rd))
+ {
+ return (-1);
+ }
+ }
+ goto set_hi_lo;
+ }
+ break;
+ /* clo */
+ case 0x21:
+ /* clz */
+ case 0x20:
+ goto set_rd;
+ break;
+ default:
+ goto no_support;
+ break;
+ }
+ break;
+
+ /* lb */
+ case 0x20:
+ /* lh */
+ case 0x21:
+ /* lwl */
+ case 0x22:
+ /* lw */
+ case 0x23:
+ /* lbu */
+ case 0x24:
+ /* lhu */
+ case 0x25:
+ /* lwr */
+ case 0x26:
+ /* ll */
+ case 0x30:
+ goto set_rt;
+ break;
+
+ /* sb */
+ case 0x28:
+ /* sh */
+ case 0x29:
+ /* swl */
+ case 0x2a:
+ /* sw */
+ case 0x2b:
+ /* swr */
+ case 0x2e:
+ /* sc */
+ case 0x38:
+ {
+ uint32_t addr;
+
+ /* addr */
+ /* base */
+ regcache_raw_read (record_regcache, (insn >> 21) & 0x1f,
+ (gdb_byte *) & addr);
+ /* offset */
+ addr += (insn >> 0) & 0xffff;
+
+ switch (opcode)
+ {
+ /* sb */
+ case 0x28:
+ if (record_arch_list_add_mem (addr, 1))
+ {
+ return (-1);
+ }
+ break;
+ /* sh */
+ case 0x29:
+ if (record_arch_list_add_mem (addr, 2))
+ {
+ return (-1);
+ }
+ break;
+ /* swl */
+ case 0x2a:
+ /* swr */
+ case 0x2e:
+ if (record_arch_list_add_mem (addr & 0xffffff00, 2))
+ {
+ return (-1);
+ }
+ break;
+ /* sw */
+ case 0x2b:
+ if (record_arch_list_add_mem (addr, 4))
+ {
+ return (-1);
+ }
+ break;
+ /* sc */
+ case 0x38:
+ if (record_arch_list_add_mem (addr, 4))
+ {
+ return (-1);
+ }
+ goto set_rt;
+ break;
+ }
+ }
+ break;
+ /* pref */
+ case 0x33:
+ break;
+
+ default:
+ goto no_support;
+ break;
+ }
+
+out:
+ if (record_delay_slot)
+ {
+ if (add_pc)
+ {
+ if (record_arch_list_add_reg (regnum->pc))
+ {
+ return (-1);
+ }
+ add_pc = 0;
+ }
+ }
+ if (record_arch_list_add_end (add_pc))
+ {
+ return (-1);
+ }
+ return (0);
+
+no_support:
+ printf_unfiltered (_
+ ("record: record and reverse function don't support 32 bits instruction 0x%08x.\n"),
+ (unsigned int) insn);
+ return (-1);
+
+set_rd:
+ {
+ uint32_t rd = (insn >> 11) & 0x1f;
+ if (rd != 0)
+ {
+ if (record_arch_list_add_reg (rd))
+ {
+ return (-1);
+ }
+ }
+ }
+ goto out;
+
+set_rt:
+ {
+ uint32_t rt = (insn >> 16) & 0x1f;
+ if (rt != 0)
+ {
+ if (record_arch_list_add_reg (rt))
+ {
+ return (-1);
+ }
+ }
+ }
+ goto out;
+
+set_imm_delay_slot_pc:
+ {
+ uint32_t imm = (insn >> 0) & 0xffff;
+ if (imm >> 15)
+ {
+ imm |= 0xffff0000;
+ }
+ imm <<= 2;
+ mips_target_addr = pc + 4 + imm;
+ }
+ goto set_delay_slot_pc;
+
+set_delay_slot_pc:
+ mips_delay_slot_addr = pc + 4;
+ record_delay_slot++;
+ goto set_pc;
+
+set_pc:
+ if (record_arch_list_add_reg (regnum->pc))
+ {
+ return (-1);
+ }
+ add_pc = 0;
+ goto out;
+
+set_hi_lo:
+ if (record_arch_list_add_reg (regnum->hi))
+ {
+ return (-1);
+ }
+ if (record_arch_list_add_reg (regnum->lo))
+ {
+ return (-1);
+ }
+ goto out;
+}
+
+/* Record the value of the memory that willbe changed in current instruction
+ to "record_arch_list".
+ Return -1 if something wrong. */
+static int mips_record (struct gdbarch *gdbarch)
+{
+ CORE_ADDR pc = read_pc ();
+
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: mips_record pc = 0x%s\n",
+ paddr_nz (pc));
+ }
+
+ if (mips_pc_is_mips16 (pc))
+ {
+ printf_unfiltered (_
+ ("record: record and reverse function don't support mips16.\n"));
+ return (-1);
+ }
+
+ if (record_delay_slot)
+ {
+ if (mips_record_32 (mips_delay_slot_addr))
+ {
+ return (-1);
+ }
+ if (mips_record_32 (mips_target_addr))
+ {
+ return (-1);
+ }
+ record_delay_slot--;
+ }
+ return (mips_record_32 (pc));
+}
+
+static void mips_record_dasm (struct gdbarch *gdbarch)
+{
+ const struct mips_regnum *regnum;
+ ULONGEST pc;
+
+ if (mips_pc_is_mips16 (read_pc ()))
+ {
+ error (_
+ ("record: record and reverse function don't support mips16.\n"));
+ }
+
+ regnum = mips_regnum (gdbarch);
+ regcache_cooked_read_unsigned (record_regcache, regnum->pc, &pc);
+ if (gdb_is_reverse)
+ {
+ pc -= 4;
+ }
+ else
+ {
+ pc += 4;
+ }
+ regcache_cooked_write_unsigned (record_regcache, regnum->pc, pc);
+}
+
static struct gdbarch *
mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
@@ -5877,6 +6608,9 @@ mips_gdbarch_init (struct gdbarch_info i
user_reg_add (gdbarch, mips_register_aliases[i].name,
value_of_mips_user_reg, &mips_register_aliases[i].regnum);
+ set_gdbarch_record (gdbarch, mips_record);
+ set_gdbarch_record_dasm (gdbarch, mips_record_dasm);
+
return gdbarch;
}
--- a/gdb/record.c
+++ b/gdb/record.c
@@ -0,0 +1,606 @@
+/* Record v0.1.2 for GDB, the GNU debugger.
+ Written by Hui Zhu <teawater@gmail.com>
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* Before the inferior resume, if the record function is open and inferior will
+ really execute (will not call "record_wait"), the GDB will call
+ function "record_message" to record the values of registrs and memory that
+ will be changed in next instrution to "record_list".
+ When GDB is in reverse debug mode and inferior is not in the begin of
+ "record_list" or GDB is in normail deubg mode and inferior is not in the
+ end of "record_list", GDB will call this function instead "target_wait". In
+ this status, function "resume" will directly return. Then inferior will
+ instead execute to call "record_wait".
+ "record_wait" will set the running message in "record_list" to inferior.
+ Then the registers and memory of inferior will change back to before. */
+
+#include "defs.h"
+#include "inferior.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "serial.h"
+#include "target.h"
+#include "exceptions.h"
+#include "gdb_string.h"
+#include "gdb_stat.h"
+#include "regcache.h"
+#include <ctype.h>
+#include <stdint.h>
+#include "mips-tdep.h"
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/file.h>
+#include "frame-unwind.h"
+#include "gdbthread.h"
+#include "exceptions.h"
+#include "infcall.h"
+#include "source.h"
+#include "top.h"
+#include "record.h"
+
+#define RECORD_REC_PROMPT "(rec) "
+#define RECORD_REV_PROMPT "(rev) "
+
+extern struct breakpoint *breakpoint_chain;
+
+record_t *record_list = NULL;
+record_t *record_arch_list_head = NULL;
+record_t *record_arch_list_tail = NULL;
+unsigned int gdb_is_recording = 0;
+int gdb_is_reverse = 0;
+int debug_record = 0;
+int record_wait_step = 0;
+int record_delay_slot = 0;
+static sigset_t record_maskall;
+static int record_get_sig = 0;
+struct regcache *record_regcache;
+static char record_gdb_prompt[20];
+
+static void
+show_debug_record (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("Record debugging is %s.\n"), value);
+}
+
+static void
+record_list_release (record_t * rec)
+{
+ record_t *tmp;
+
+ while (rec)
+ {
+ tmp = rec;
+ rec = rec->prev;
+ xfree (tmp);
+ }
+}
+
+/* Before inferior step (When GDB record the running message, inferior only can
+ step.), GDB will call this function to record the values to "record_list".
+ This function will call "gdbarch_record" to record the running message of
+ inferior and set them to "record_arch_list". And add it to "record_list". */
+void
+record_message (struct gdbarch *gdbarch)
+{
+ int ret;
+
+ record_arch_list_head = NULL;
+ record_arch_list_tail = NULL;
+ record_regcache = get_current_regcache ();
+
+ ret = gdbarch_record (gdbarch);
+ if (ret > 0)
+ {
+ record_list_release (record_arch_list_tail);
+ error (_("record: record pause the program."));
+ }
+ if (ret < 0)
+ {
+ record_delay_slot = 0;
+ record_list_release (record_arch_list_tail);
+ error (_("record: record message error."));
+ }
+
+ if (record_list)
+ {
+ record_list->next = record_arch_list_head;
+ record_arch_list_head->prev = record_list;
+ record_list = record_arch_list_tail;
+ }
+ else
+ {
+ record_list = record_arch_list_tail;
+ }
+}
+
+/* Add a record_t to "record_arch_list". */
+static void
+record_arch_list_add (record_t * rec)
+{
+ if (record_arch_list_tail)
+ {
+ record_arch_list_tail->next = rec;
+ rec->prev = record_arch_list_tail;
+ record_arch_list_tail = rec;
+ }
+ else
+ {
+ record_arch_list_head = rec;
+ record_arch_list_tail = rec;
+ }
+}
+
+/* Record the value of a register("num") to "record_arch_list". */
+int
+record_arch_list_add_reg (int num)
+{
+ record_t *rec;
+
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: add reg num = %d to arch list.\n", num);
+ }
+
+ rec = (record_t *) xmalloc (sizeof (record_t));
+ if (!rec)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
+ return (-1);
+ }
+ rec->u.reg.val = (gdb_byte *) xmalloc (MAX_REGISTER_SIZE);
+ if (!rec->u.reg.val)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
+ xfree (rec);
+ return (-1);
+ }
+ rec->prev = NULL;
+ rec->next = NULL;
+ rec->type = record_reg;
+ rec->u.reg.num = num;
+
+ regcache_raw_read (record_regcache, num, rec->u.reg.val);
+
+ record_arch_list_add (rec);
+
+ return (0);
+}
+
+/* Record the value of a part of memroy that address is "addr" and length is
+ "len" to "record_arch_list". */
+int
+record_arch_list_add_mem (CORE_ADDR addr, int len)
+{
+ record_t *rec;
+
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: add mem addr = 0x%s len = %d to arch list.\n",
+ paddr_nz (addr), len);
+ }
+
+ rec = (record_t *) xmalloc (sizeof (record_t));
+ if (!rec)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
+ return (-1);
+ }
+ rec->u.mem.val = (gdb_byte *) xmalloc (len);
+ if (!rec->u.mem.val)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
+ xfree (rec);
+ return (-1);
+ }
+ rec->prev = NULL;
+ rec->next = NULL;
+ rec->type = record_mem;
+ rec->u.mem.addr = addr;
+ rec->u.mem.len = len;
+
+ if (target_read_memory (addr, rec->u.mem.val, len))
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: read memory addr = 0x%s len = %d error.\n",
+ paddr_nz (addr), len);
+ xfree (rec->u.mem.val);
+ xfree (rec);
+ return (-1);
+ }
+
+ record_arch_list_add (rec);
+
+ return (0);
+}
+
+/* Add a "record_end" type record_t to "record_arch_list". */
+int
+record_arch_list_add_end (int need_dasm)
+{
+ record_t *rec;
+
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: add end need_dasm = %d to arch list.\n",
+ need_dasm);
+ }
+
+ rec = (record_t *) xmalloc (sizeof (record_t));
+ if (!rec)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
+ return (-1);
+ }
+ 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_sig_handler (int signo)
+{
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: get a signal\n");
+ }
+ record_wait_step = 1;
+ record_get_sig = 1;
+}
+
+/* When GDB is in reverse debug mode and inferior is not in the begin of
+ "record_list" or GDB is in normail deubg mode and inferior is not in the
+ end of "record_list", GDB will call this function instead "target_wait". In
+ this status, function "resume" will directly return. Then inferior will
+ instead execute to call "record_wait".
+ "record_wait" will set the running message in "record_list" to inferior.
+ Then the registers and memory of inferior will change back to before. */
+ptid_t
+record_wait (struct gdbarch *gdbarch, ptid_t ptid, struct target_waitstatus *status)
+{
+ struct sigaction act, old_act;
+ static int state = 0; /* 0 normal 1 to the end 2 to the begin */
+ int con = 1;
+ int insn_end = 0;
+ int need_dasm = 0;
+ struct regcache *regcache = get_current_regcache ();
+
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: record_wait step = %d\n",
+ record_wait_step);
+ }
+
+ record_get_sig = 0;
+ act.sa_handler = record_sig_handler;
+ act.sa_mask = record_maskall;
+ act.sa_flags = SA_RESTART;
+ if (sigaction (SIGINT, &act, &old_act))
+ {
+ perror_with_name (_("sigaction"));
+ }
+
+ do
+ {
+ /* check state */
+ if ((gdb_is_reverse && !record_list->prev && state == 2)
+ || (!gdb_is_reverse && !record_list->next && state == 1))
+ {
+ if (state == 1)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: running to the end of record list.\n");
+ }
+ else if (state == 2)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: running to the begin of record list.\n");
+ }
+ stop_soon = STOP_QUIETLY;
+ break;
+ }
+ state = 0;
+
+ /* set register and memory according to record_list */
+ if (record_list->type == record_reg)
+ {
+ /* reg */
+ gdb_byte reg[MAX_REGISTER_SIZE];
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: record_list reg num = %d to arch list.\n",
+ record_list->u.reg.num);
+ }
+ regcache_cooked_read (regcache, record_list->u.reg.num, reg);
+ regcache_cooked_write (regcache, record_list->u.reg.num,
+ record_list->u.reg.val);
+ memcpy (record_list->u.reg.val, reg, MAX_REGISTER_SIZE);
+ }
+ else if (record_list->type == record_mem)
+ {
+ /* mem */
+ gdb_byte mem[record_list->u.mem.len];
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: record_list mem addr = 0x%s len = %d to current.\n",
+ paddr_nz (record_list->u.mem.addr),
+ record_list->u.mem.len);
+ }
+ if (target_read_memory
+ (record_list->u.mem.addr, mem, record_list->u.mem.len))
+ {
+ error (_("record: read memory addr = 0x%s len = %d error."),
+ paddr_nz (record_list->u.mem.addr),
+ record_list->u.mem.len);
+ }
+ if (target_write_memory
+ (record_list->u.mem.addr, record_list->u.mem.val,
+ record_list->u.mem.len))
+ {
+ error (_("record: write memory addr = 0x%s len = %d error."),
+ paddr_nz (record_list->u.mem.addr),
+ record_list->u.mem.len);
+ }
+ memcpy (record_list->u.mem.val, mem, record_list->u.mem.len);
+ }
+ else
+ {
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: record_list end need_dasm = %d to current.\n",
+ record_list->u.need_dasm);
+ }
+
+ need_dasm = record_list->u.need_dasm;
+ if (!gdb_is_reverse)
+ {
+ insn_end = 1;
+ }
+ }
+
+ if (gdb_is_reverse)
+ {
+ if (record_list->prev)
+ {
+ record_list = record_list->prev;
+ if (!record_list->type)
+ {
+ insn_end = 1;
+ }
+ }
+ else
+ {
+ state = 2;
+ insn_end = 1;
+ }
+ }
+ else
+ {
+ if (record_list->next)
+ {
+ record_list = record_list->next;
+ }
+ else
+ {
+ state = 1;
+ }
+ }
+
+ if (insn_end)
+ {
+ struct breakpoint *b;
+ CORE_ADDR tmp_pc;
+
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: insn end need_dasm = %d to current.\n",
+ need_dasm);
+ }
+
+ if (need_dasm)
+ {
+ gdbarch_record_dasm (gdbarch);
+ }
+
+ //registers_changed ();
+ tmp_pc = read_pc ();
+
+ /* end */
+ if (record_wait_step)
+ {
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog, "record: step.\n");
+ }
+ con = 0;
+ }
+
+ /* check breakpoint */
+ for (b = breakpoint_chain; b; b = b->next)
+ {
+ if (b->loc->inserted)
+ {
+ if (b->loc->target_info.placed_address == tmp_pc)
+ {
+ if (debug_record)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "record: break at 0x%s.\n",
+ paddr_nz (tmp_pc));
+ }
+ con = 0;
+ break;
+ }
+ }
+ }
+
+ insn_end = 0;
+ }
+ }
+ while (con);
+
+ if (sigaction (SIGALRM, &old_act, NULL))
+ {
+ perror_with_name (_("sigaction"));
+ }
+
+ status->kind = TARGET_WAITKIND_STOPPED;
+ if (record_get_sig)
+ {
+ status->value.sig = TARGET_SIGNAL_INT;
+ }
+ else
+ {
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ }
+
+ return (inferior_ptid);
+}
+
+void
+record_close (void)
+{
+ gdb_is_recording = 0;
+ gdb_is_reverse = 0;
+ record_list_release (record_list);
+ record_list = NULL;
+ record_delay_slot = 0;
+ printf_unfiltered (_("record: record and reverse function is stopped.\n"));
+}
+
+static void
+cmd_record_start (char *args, int from_tty)
+{
+ /* check exec */
+ if (!target_has_execution)
+ {
+ error (_("record: the program is not being run."));
+ }
+
+ if (!gdbarch_record_p (current_gdbarch))
+ {
+ error (_("record: the current gdbarch don't support record function."));
+ }
+
+ if (gdb_is_recording)
+ {
+ printf_unfiltered (_
+ ("record: record and reverse function has already been started.\n"));
+ }
+ else
+ {
+ char *tmp;
+
+ gdb_is_recording = 1;
+ printf_unfiltered (_
+ ("record: record and reverse function is started.\n"));
+
+ tmp = get_prompt ();
+ snprintf (record_gdb_prompt, 20, "%s", tmp);
+ set_prompt (RECORD_REC_PROMPT);
+ }
+}
+
+static void
+cmd_record_stop (char *args, int from_tty)
+{
+ /* check exec */
+ if (!target_has_execution)
+ {
+ error (_("record: the program is not being run."));
+ }
+
+ if (!gdbarch_record_p (current_gdbarch))
+ {
+ error (_("record: the current gdbarch don't support record function."));
+ }
+
+ if (gdb_is_recording)
+ {
+ record_close ();
+ set_prompt (record_gdb_prompt);
+ }
+ else
+ {
+ printf_unfiltered (_
+ ("record: record and reverse function is not started.\n"));
+ }
+}
+
+static void
+cmd_reverse (char *args, int from_tty)
+{
+ if (gdb_is_reverse)
+ {
+ gdb_is_reverse = 0;
+ printf_unfiltered (_("record: GDB is set to normal debug mode.\n"));
+ set_prompt (RECORD_REC_PROMPT);
+ }
+ else
+ {
+ if (!record_list)
+ {
+ error (_("record: record and reverse function is not started."));
+ }
+ gdb_is_reverse = 1;
+ printf_unfiltered (_("record: GDB is set to reverse debug mode.\n"));
+ set_prompt (RECORD_REV_PROMPT);
+ }
+}
+
+void
+_initialize_record (void)
+{
+ /* init record_maskall */
+ if (sigfillset (&record_maskall) == -1)
+ {
+ perror_with_name (_("sigfillset"));
+ }
+
+ add_setshow_zinteger_cmd ("record", class_maintenance, &debug_record,
+ _("Set record debugging."),
+ _("Show record debugging."),
+ _
+ ("When non-zero, record specific debugging is enabled."),
+ NULL, show_debug_record, &setdebuglist,
+ &showdebuglist);
+ add_com ("record", class_obscure, cmd_record_start,
+ _("Start the record and reverse function."));
+ add_com_alias ("rec", "record", class_obscure, 1);
+ add_com ("stoprecord", class_obscure, cmd_record_stop,
+ _("Stop the record and reverse function."));
+ add_com_alias ("srec", "stoprecord", class_obscure, 1);
+ add_com ("reverse", class_obscure, cmd_reverse,
+ _("Set GDB to the reverse debug mode or the normal debug mode."));
+ add_com_alias ("rev", "reverse", class_obscure, 1);
+}
--- a/gdb/record.h
+++ b/gdb/record.h
@@ -0,0 +1,81 @@
+/* Record v0.1.2 for GDB, the GNU debugger.
+ Written by Hui Zhu <teawater@gmail.com>
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _RECORD_H_
+#define _RECORD_H_
+
+typedef struct record_reg_s
+{
+ int num;
+ gdb_byte *val;
+} record_reg_t;
+
+typedef struct record_mem_s
+{
+ CORE_ADDR addr;
+ int len;
+ gdb_byte *val;
+} record_mem_t;
+
+enum record_type {
+ record_end = 0,
+ record_reg,
+ record_mem
+};
+
+/* This is the core struct of record function.
+ An entity of record_t is a record of the value change of a register
+ ("record_reg") or a part of memory ("record_mem"). And Each instruction must
+ has a record_t ("record_end") that point out this is the last record_t of
+ this instruction.
+ Each record_t is linked to "record_list" by "prev" and "next".
+ */
+typedef struct record_s
+{
+ struct record_s *prev;
+ struct record_s *next;
+ enum record_type type;
+ union
+ {
+ /* reg */
+ record_reg_t reg;
+ /* mem */
+ record_mem_t mem;
+ /* end */
+ int need_dasm;
+ } u;
+} record_t;
+
+extern record_t *record_list;
+extern record_t *record_arch_list_head;
+extern record_t *record_arch_list_tail;
+extern int record_arch_need_dasm;
+extern unsigned int gdb_is_recording;
+extern int gdb_is_reverse;
+extern int debug_record;
+extern int record_wait_step;
+extern int record_delay_slot;
+extern struct regcache *record_regcache;
+
+extern void record_message (struct gdbarch *gdbarch);
+extern int record_arch_list_add_reg (int num);
+extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
+extern int record_arch_list_add_end (int need_dasm);
+extern ptid_t record_wait (struct gdbarch *gdbarch, ptid_t ptid, struct target_waitstatus *status);
+extern void record_close (void);
+#endif //_RECORD_H_
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -39,6 +39,7 @@
#include "gdbcore.h"
#include "exceptions.h"
#include "target-descriptions.h"
+#include "record.h"
static void target_info (char *, int);
@@ -1702,6 +1703,16 @@ target_follow_fork (int follow_child)
"could not find a target to follow fork");
}
+void
+target_mourn_inferior (void)
+{
+ if (gdb_is_recording)
+ {
+ record_close ();
+ }
+ (*current_target.to_mourn_inferior) ();
+}
+
/* Look for a target which can describe architectural features, starting
from TARGET. If we find one, return its description. */
@@ -2065,6 +2076,10 @@ debug_to_close (int quitting)
void
target_close (struct target_ops *targ, int quitting)
{
+ if (gdb_is_recording)
+ {
+ record_close ();
+ }
if (targ->to_xclose != NULL)
targ->to_xclose (targ, quitting);
else if (targ->to_close != NULL)
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -861,8 +861,7 @@ int target_follow_fork (int follow_child
/* The inferior process has died. Do what is right. */
-#define target_mourn_inferior() \
- (*current_target.to_mourn_inferior) ()
+extern void target_mourn_inferior (void);
/* Does target have enough data to do a run or attach command? */
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-04-23 8:55 GDB record patch 0.1.3.1 for GDB-6.8 release Tea
@ 2008-05-20 4:33 ` Thiago Jung Bauermann
2008-05-20 6:38 ` Daniel Jacobowitz
` (2 more replies)
2008-05-23 3:52 ` Pedro Alves
1 sibling, 3 replies; 33+ messages in thread
From: Thiago Jung Bauermann @ 2008-05-20 4:33 UTC (permalink / raw)
To: Tea; +Cc: Michael Snyder, gdb-patches
Hi teawater,
On Wed, 2008-04-23 at 14:16 +0800, Tea wrote:
> most part of GDB record patch 0.1.3.1 is same with GDB record patch
> 0.1.3 (http://sourceware.org/ml/gdb-patches/2008-04/msg00300.html). I
> just did some change according to your mail. I must express the
> particularly grateful to you.
Thanks for your changes. They made the patch easier to review, and put
it a bit closer to being merged, IMHO.
Here are my comments on the patch. I'm sorry I took so long to get to
it, but it is a big patch, and it takes some time to understand it. :-)
General comments:
- I think it would be useful to put a limit on the amount of
entries that are kept in the record list, to avoid having GDB use
all of the machine's memory on a big program. A way to say "record the
last 50k instructions" would be nice, IMHO. This would make it
practical to use the functionality when debugging larger programs.
But perhaps this should be left as an improvement for the future?
- A question: if you record changes, then reverse GDB through them but
stop it half-way, and then set the direction (gear? :-) ) back to
forward, GDB will just play back the changes it has recorded, and not
continue the inferior until it reaches the end of the record list,
right?
If so this means that if the user goes back a few insns, modifies a
variable which is used in an if condition, the code will still appear
to take the branch it took before. This is unintuitive and may lead
the inferior to an undefined state, impossible to achieve by regular
runs of the program. So I think GDB either needs to be put in a
"read-only" mode where it refuses to change inferior memory and
registers, or it needs to discard the records made after the point
where the change in inferior state was made. What do you think?
- Before the patch is committed, the user manual needs to be updated to
explain how to use this feature, and also talk about its limitations.
It would be better to extend the GDB Internals document as well, to
provide an outline on how reversible debugging is implemented, and
what needs to be done to make it support a new platform. IMHO this can
wait until more discussion goes into the feature, to avoid having to
change the documentation later.
- Also, before the patch is committed it needs to be refreshed to apply
against CVS HEAD and not 6.8. Also, you can choose to do this closer
to when the patch is committed to avoid having to re-refresh it in
case CVS HEAD changes too much.
- Disclaimer: my knowledge of infrun.c and infcmd.c is very limited.
I took only a cursory look at the changes there.
I'll read the patch again another day, to see if I have anything else
to add.
Now, focusing on the patch:
> i386-linux-tdep.c | 2533 +++++++++++++++++++++++++++++++++++++++++++++++++
> i386-tdep.c | 2769 +++++++++++++++++++++++++++++++++++++++++++++++++++---
This feature increases the size of these files a great deal. They are
currently 459 lines and 2561 lines respectively (as of GDB 6.8). Perhaps
creating separate files for platform-specific record code makes things
more manageable (e.g., i386-linux-rec.c and i386-rec.c)? I guess that's
a question to the GDB maintainers.
> mips-tdep.c | 734 ++++++++++++++
OTOH, mips-tdep.c has originally 6124 lines and this patch adds
relatively little to that.
> --- a/gdb/gdbarch.c
> +++ b/gdb/gdbarch.c
> @@ -230,6 +230,8 @@ struct gdbarch
> gdbarch_core_read_description_ftype *core_read_description;
> gdbarch_static_transform_name_ftype *static_transform_name;
> int sofun_address_maybe_missing;
> + gdbarch_record_ftype *record;
> + gdbarch_record_dasm_ftype *record_dasm;
> };
>
>
> @@ -352,6 +354,8 @@ struct gdbarch startup_gdbarch =
> 0, /* core_read_description */
> 0, /* static_transform_name */
> 0, /* sofun_address_maybe_missing */
> + NULL,
> + NULL,
> /* startup_gdbarch() */
> };
There should be comments in the lines above mentioning what those NULLs
are for (record and record_dasm), like in the other elements of the
structure.
> --- a/gdb/i386-linux-tdep.c
> +++ b/gdb/i386-linux-tdep.c
> @@ -35,6 +35,9 @@
> #include "solib-svr4.h"
> #include "symtab.h"
>
> +#include "record.h"
> +#include <stdint.h>
Can we just include <stdint.h> and not worry, now? I think so, but not
sure.
Also, record.h needs to be added to i386-linux-tdep.c's dependencies
list in Makefile.in. Same applies to other files which include record.h.
> @@ -335,6 +338,2533 @@ i386_linux_write_pc (struct regcache *re
> restarted. */
> regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1);
> }
> +
> +
> +/* These macros are the size of the type that will be use in system call. The values of
> + these macros are gotten from Linux Kernel source. */
> +#define I386_RECORD_SIZE__old_kernel_stat 32
> +#define I386_RECORD_SIZE_tms 16
I wonder if there is a way to get these sizes by including the Linux
kernel header files? The way it is done here looks very fragile and tied
to a specific Linux kernel version to me...
Granted, using kernel includes will still be fragile and
version-specific, but at least to update GDB only a recompile is needed,
as oposed to manually figuring out and editing these #defines.
Since glibc has to have access to these structures anyway, I think it is
possible. And this also means that at least some binary compatibility
stability is to be expected, right?
Same concerns regarding the other #defines following these.
> + if (!need_dasm)
> + {
> + if (record_arch_list_add_reg (I386_EIP_REGNUM))
> + {
> + return (-1);
> + }
> + }
> + if (record_arch_list_add_end (need_dasm))
> + {
> + return (-1);
> + }
Looking at i386_record, need_dasm is always zero so the variable can be
removed, and the call to record_arch_list_add_reg above doens't need to
be inside the if (!need_dasm).
> + if (record_list && (record_list->next || gdb_is_reverse))
> + {
> + discard_cleanups (old_cleanups);
> + record_wait_step = step;
> + return;
> + }
I think it's better to have a comment above the if condition explaining
what it means. If I understood things correctly, if the condition is
true then GDB is not really executing the inferior but merely playing
back the recorded states stored by the record functionality, right?
> @@ -1026,10 +1047,18 @@ wait_for_inferior (int treat_exec_as_sig
>
> while (1)
> {
> - if (deprecated_target_wait_hook)
> - ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
> + if (record_list && (record_list->next || gdb_is_reverse))
> + {
> + ecs->ptid = record_wait (current_gdbarch, ecs->waiton_ptid, ecs->wp);
> + }
Same remark here, about having a comment explaining the if condition.
> @@ -2004,10 +2033,19 @@ handle_inferior_event (struct execution_
> SPARC. */
>
> if (stop_signal == TARGET_SIGNAL_TRAP)
> - ecs->random_signal
> - = !(bpstat_explains_signal (stop_bpstat)
> - || stepping_over_breakpoint
> - || (step_range_end && step_resume_breakpoint == NULL));
> + {
> + if (gdb_is_reverse || gdb_is_recording)
> + {
> + ecs->random_signal = 0;
> + }
> + else
> + {
> + ecs->random_signal
> + = !(bpstat_explains_signal (stop_bpstat)
> + || stepping_over_breakpoint
> + || (step_range_end && step_resume_breakpoint == NULL));
> + }
> + }
IMHO, it is clearer to just extend the expression for random_signal,
rather than introduce a special case for reversible debugging. What
about the following?
- || (step_range_end && step_resume_breakpoint == NULL));
+ || (step_range_end && step_resume_breakpoint == NULL)
+ || gdb_is_reverse
+ || gdb_is_recording);
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
In addition to the changes you made to Makefile.in, you need to add a
record.o target listing the source and header files it depends on. See
the other .o targets there for an example.
> +static void
> +record_list_release (record_t * rec)
> +{
> + record_t *tmp;
> +
> + while (rec)
> + {
> + tmp = rec;
> + rec = rec->prev;
> + xfree (tmp);
> + }
> +}
This function will leak memory. You also need to free rec->u.reg.val or
rec->u.mem.val, depending on the type of the record.
> + rec = (record_t *) xmalloc (sizeof (record_t));
> + if (!rec)
> + {
> + fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
> + return (-1);
> + }
xmalloc will make GDB exit if memory is exhausted, so there's no need to
check the return value.
> + else if (record_list->type == record_mem)
> + {
> + /* mem */
> + gdb_byte mem[record_list->u.mem.len];
Variable length array is a C99 construct. Currently GDB code needs to
restrict itself to at most C90 features, so you will need to explicitly
allocate memory here. If there are other places where this syntax is
used, they need to be changed as well.
> + //registers_changed ();
The commented out call should be removed.
> +void
> +record_close (void)
> +{
> + gdb_is_recording = 0;
> + gdb_is_reverse = 0;
> + record_list_release (record_list);
This function will leak memory if record_list doesn't point to the very
end of the linked list. From what I understood of the code, record_close
may be called when GDB is playing back the records, so record_list can
be pointing at any element of the list.
--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-20 4:33 ` Thiago Jung Bauermann
@ 2008-05-20 6:38 ` Daniel Jacobowitz
2008-05-20 15:32 ` Tea
2008-05-20 15:33 ` Tea
2008-05-21 17:14 ` Tea
2 siblings, 1 reply; 33+ messages in thread
From: Daniel Jacobowitz @ 2008-05-20 6:38 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Tea, Michael Snyder, gdb-patches
On Mon, May 19, 2008 at 06:19:15PM -0300, Thiago Jung Bauermann wrote:
> I wonder if there is a way to get these sizes by including the Linux
> kernel header files? The way it is done here looks very fragile and tied
> to a specific Linux kernel version to me...
>
> Granted, using kernel includes will still be fragile and
> version-specific, but at least to update GDB only a recompile is needed,
> as oposed to manually figuring out and editing these #defines.
No, this way is better. These are not types used internally by the
kernel; they're part of its public interface and will not change.
And the headers are in good shape nowadays but the clean headers are
not universally available yet.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-20 6:38 ` Daniel Jacobowitz
@ 2008-05-20 15:32 ` Tea
2008-05-20 18:51 ` Michael Snyder
0 siblings, 1 reply; 33+ messages in thread
From: Tea @ 2008-05-20 15:32 UTC (permalink / raw)
To: drow, Thiago Jung Bauermann, Tea, Michael Snyder, gdb-patches
Agree with Daniel.
I think current way is better than include Linux kernel header files.
To compile GDB with Linux KERNEL? I think it will make compile GDB not
very easy. If the Linux Kernel change. The user need re-compile the
GDB?
Or add Linux Kernel files to GDB directory? It looks not very
professional. And maybe will cause some copyright problem.
And this types size will not change very continually. The GLIBC use it
too. The kernel more like add new types than change the old types.
Of course, add more comments for these size #define are needed. It is
a big job for me. It make me crazy in before. :)
Thanks,
teawater
On Tue, May 20, 2008 at 5:29 AM, Daniel Jacobowitz <drow@false.org> wrote:
>
> On Mon, May 19, 2008 at 06:19:15PM -0300, Thiago Jung Bauermann wrote:
> > I wonder if there is a way to get these sizes by including the Linux
> > kernel header files? The way it is done here looks very fragile and tied
> > to a specific Linux kernel version to me...
> >
> > Granted, using kernel includes will still be fragile and
> > version-specific, but at least to update GDB only a recompile is needed,
> > as oposed to manually figuring out and editing these #defines.
>
> No, this way is better. These are not types used internally by the
> kernel; they're part of its public interface and will not change.
> And the headers are in good shape nowadays but the clean headers are
> not universally available yet.
>
>
> --
> Daniel Jacobowitz
> CodeSourcery
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-20 4:33 ` Thiago Jung Bauermann
2008-05-20 6:38 ` Daniel Jacobowitz
@ 2008-05-20 15:33 ` Tea
2008-05-21 17:14 ` Tea
2 siblings, 0 replies; 33+ messages in thread
From: Tea @ 2008-05-20 15:33 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Michael Snyder, gdb-patches
Hi Thiago,
Thank your help. It is so great.
I will modify record according to your mail.
Thanks,
teawater
On Tue, May 20, 2008 at 5:19 AM, Thiago Jung Bauermann
<bauerman@br.ibm.com> wrote:
> Hi teawater,
>
> On Wed, 2008-04-23 at 14:16 +0800, Tea wrote:
>> most part of GDB record patch 0.1.3.1 is same with GDB record patch
>> 0.1.3 (http://sourceware.org/ml/gdb-patches/2008-04/msg00300.html). I
>> just did some change according to your mail. I must express the
>> particularly grateful to you.
>
> Thanks for your changes. They made the patch easier to review, and put
> it a bit closer to being merged, IMHO.
>
> Here are my comments on the patch. I'm sorry I took so long to get to
> it, but it is a big patch, and it takes some time to understand it. :-)
>
> General comments:
>
> - I think it would be useful to put a limit on the amount of
> entries that are kept in the record list, to avoid having GDB use
> all of the machine's memory on a big program. A way to say "record the
> last 50k instructions" would be nice, IMHO. This would make it
> practical to use the functionality when debugging larger programs.
> But perhaps this should be left as an improvement for the future?
>
> - A question: if you record changes, then reverse GDB through them but
> stop it half-way, and then set the direction (gear? :-) ) back to
> forward, GDB will just play back the changes it has recorded, and not
> continue the inferior until it reaches the end of the record list,
> right?
>
> If so this means that if the user goes back a few insns, modifies a
> variable which is used in an if condition, the code will still appear
> to take the branch it took before. This is unintuitive and may lead
> the inferior to an undefined state, impossible to achieve by regular
> runs of the program. So I think GDB either needs to be put in a
> "read-only" mode where it refuses to change inferior memory and
> registers, or it needs to discard the records made after the point
> where the change in inferior state was made. What do you think?
>
> - Before the patch is committed, the user manual needs to be updated to
> explain how to use this feature, and also talk about its limitations.
> It would be better to extend the GDB Internals document as well, to
> provide an outline on how reversible debugging is implemented, and
> what needs to be done to make it support a new platform. IMHO this can
> wait until more discussion goes into the feature, to avoid having to
> change the documentation later.
>
> - Also, before the patch is committed it needs to be refreshed to apply
> against CVS HEAD and not 6.8. Also, you can choose to do this closer
> to when the patch is committed to avoid having to re-refresh it in
> case CVS HEAD changes too much.
>
> - Disclaimer: my knowledge of infrun.c and infcmd.c is very limited.
> I took only a cursory look at the changes there.
>
> I'll read the patch again another day, to see if I have anything else
> to add.
>
> Now, focusing on the patch:
>
>> i386-linux-tdep.c | 2533 +++++++++++++++++++++++++++++++++++++++++++++++++
>> i386-tdep.c | 2769 +++++++++++++++++++++++++++++++++++++++++++++++++++---
>
> This feature increases the size of these files a great deal. They are
> currently 459 lines and 2561 lines respectively (as of GDB 6.8). Perhaps
> creating separate files for platform-specific record code makes things
> more manageable (e.g., i386-linux-rec.c and i386-rec.c)? I guess that's
> a question to the GDB maintainers.
>
>> mips-tdep.c | 734 ++++++++++++++
>
> OTOH, mips-tdep.c has originally 6124 lines and this patch adds
> relatively little to that.
>
>> --- a/gdb/gdbarch.c
>> +++ b/gdb/gdbarch.c
>> @@ -230,6 +230,8 @@ struct gdbarch
>> gdbarch_core_read_description_ftype *core_read_description;
>> gdbarch_static_transform_name_ftype *static_transform_name;
>> int sofun_address_maybe_missing;
>> + gdbarch_record_ftype *record;
>> + gdbarch_record_dasm_ftype *record_dasm;
>> };
>>
>>
>> @@ -352,6 +354,8 @@ struct gdbarch startup_gdbarch =
>> 0, /* core_read_description */
>> 0, /* static_transform_name */
>> 0, /* sofun_address_maybe_missing */
>> + NULL,
>> + NULL,
>> /* startup_gdbarch() */
>> };
>
> There should be comments in the lines above mentioning what those NULLs
> are for (record and record_dasm), like in the other elements of the
> structure.
>
>> --- a/gdb/i386-linux-tdep.c
>> +++ b/gdb/i386-linux-tdep.c
>> @@ -35,6 +35,9 @@
>> #include "solib-svr4.h"
>> #include "symtab.h"
>>
>> +#include "record.h"
>> +#include <stdint.h>
>
> Can we just include <stdint.h> and not worry, now? I think so, but not
> sure.
>
> Also, record.h needs to be added to i386-linux-tdep.c's dependencies
> list in Makefile.in. Same applies to other files which include record.h.
>
>> @@ -335,6 +338,2533 @@ i386_linux_write_pc (struct regcache *re
>> restarted. */
>> regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1);
>> }
>> +
>> +
>> +/* These macros are the size of the type that will be use in system call. The values of
>> + these macros are gotten from Linux Kernel source. */
>> +#define I386_RECORD_SIZE__old_kernel_stat 32
>> +#define I386_RECORD_SIZE_tms 16
>
> I wonder if there is a way to get these sizes by including the Linux
> kernel header files? The way it is done here looks very fragile and tied
> to a specific Linux kernel version to me...
>
> Granted, using kernel includes will still be fragile and
> version-specific, but at least to update GDB only a recompile is needed,
> as oposed to manually figuring out and editing these #defines.
>
> Since glibc has to have access to these structures anyway, I think it is
> possible. And this also means that at least some binary compatibility
> stability is to be expected, right?
>
> Same concerns regarding the other #defines following these.
>
>> + if (!need_dasm)
>> + {
>> + if (record_arch_list_add_reg (I386_EIP_REGNUM))
>> + {
>> + return (-1);
>> + }
>> + }
>> + if (record_arch_list_add_end (need_dasm))
>> + {
>> + return (-1);
>> + }
>
> Looking at i386_record, need_dasm is always zero so the variable can be
> removed, and the call to record_arch_list_add_reg above doens't need to
> be inside the if (!need_dasm).
>
>> + if (record_list && (record_list->next || gdb_is_reverse))
>> + {
>> + discard_cleanups (old_cleanups);
>> + record_wait_step = step;
>> + return;
>> + }
>
> I think it's better to have a comment above the if condition explaining
> what it means. If I understood things correctly, if the condition is
> true then GDB is not really executing the inferior but merely playing
> back the recorded states stored by the record functionality, right?
>
>> @@ -1026,10 +1047,18 @@ wait_for_inferior (int treat_exec_as_sig
>>
>> while (1)
>> {
>> - if (deprecated_target_wait_hook)
>> - ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
>> + if (record_list && (record_list->next || gdb_is_reverse))
>> + {
>> + ecs->ptid = record_wait (current_gdbarch, ecs->waiton_ptid, ecs->wp);
>> + }
>
> Same remark here, about having a comment explaining the if condition.
>
>> @@ -2004,10 +2033,19 @@ handle_inferior_event (struct execution_
>> SPARC. */
>>
>> if (stop_signal == TARGET_SIGNAL_TRAP)
>> - ecs->random_signal
>> - = !(bpstat_explains_signal (stop_bpstat)
>> - || stepping_over_breakpoint
>> - || (step_range_end && step_resume_breakpoint == NULL));
>> + {
>> + if (gdb_is_reverse || gdb_is_recording)
>> + {
>> + ecs->random_signal = 0;
>> + }
>> + else
>> + {
>> + ecs->random_signal
>> + = !(bpstat_explains_signal (stop_bpstat)
>> + || stepping_over_breakpoint
>> + || (step_range_end && step_resume_breakpoint == NULL));
>> + }
>> + }
>
> IMHO, it is clearer to just extend the expression for random_signal,
> rather than introduce a special case for reversible debugging. What
> about the following?
>
> - || (step_range_end && step_resume_breakpoint == NULL));
> + || (step_range_end && step_resume_breakpoint == NULL)
> + || gdb_is_reverse
> + || gdb_is_recording);
>
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>
> In addition to the changes you made to Makefile.in, you need to add a
> record.o target listing the source and header files it depends on. See
> the other .o targets there for an example.
>
>> +static void
>> +record_list_release (record_t * rec)
>> +{
>> + record_t *tmp;
>> +
>> + while (rec)
>> + {
>> + tmp = rec;
>> + rec = rec->prev;
>> + xfree (tmp);
>> + }
>> +}
>
> This function will leak memory. You also need to free rec->u.reg.val or
> rec->u.mem.val, depending on the type of the record.
>
>> + rec = (record_t *) xmalloc (sizeof (record_t));
>> + if (!rec)
>> + {
>> + fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
>> + return (-1);
>> + }
>
> xmalloc will make GDB exit if memory is exhausted, so there's no need to
> check the return value.
>
>> + else if (record_list->type == record_mem)
>> + {
>> + /* mem */
>> + gdb_byte mem[record_list->u.mem.len];
>
> Variable length array is a C99 construct. Currently GDB code needs to
> restrict itself to at most C90 features, so you will need to explicitly
> allocate memory here. If there are other places where this syntax is
> used, they need to be changed as well.
>
>> + //registers_changed ();
>
> The commented out call should be removed.
>
>> +void
>> +record_close (void)
>> +{
>> + gdb_is_recording = 0;
>> + gdb_is_reverse = 0;
>> + record_list_release (record_list);
>
> This function will leak memory if record_list doesn't point to the very
> end of the linked list. From what I understood of the code, record_close
> may be called when GDB is playing back the records, so record_list can
> be pointing at any element of the list.
>
> --
> []'s
> Thiago Jung Bauermann
> Software Engineer
> IBM Linux Technology Center
>
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-20 15:32 ` Tea
@ 2008-05-20 18:51 ` Michael Snyder
2008-05-21 17:26 ` Tea
0 siblings, 1 reply; 33+ messages in thread
From: Michael Snyder @ 2008-05-20 18:51 UTC (permalink / raw)
To: Tea; +Cc: drow, Thiago Jung Bauermann, gdb-patches
On Tue, 2008-05-20 at 11:55 +0800, Tea wrote:
> Agree with Daniel.
> I think current way is better than include Linux kernel header files.
>
> To compile GDB with Linux KERNEL? I think it will make compile GDB not
> very easy. If the Linux Kernel change. The user need re-compile the
> GDB?
> Or add Linux Kernel files to GDB directory? It looks not very
> professional. And maybe will cause some copyright problem.
>
> And this types size will not change very continually. The GLIBC use it
> too. The kernel more like add new types than change the old types.
There is another possibility. You might build something
resembling gdbserver, and put the record/playback functionality
in there. Have gdb talk to it by the remote serial protocol
(over a socket, of course).
There is an old branch in the cvs repository where we have
stashed away a version of gdb that has some extra "reverse"
syntax in the remote protocol.
This would have the advantage of a clear separation layer,
so that gdb would not have to be "poluted" by foreign header
files with different copyrights and licensing, plus keeping
a big chunk of complex code separate from gdb itself.
Plus, you could now reverse-debug from one host to another,
even across different architectures.
Just an idea...
Michael
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-20 4:33 ` Thiago Jung Bauermann
2008-05-20 6:38 ` Daniel Jacobowitz
2008-05-20 15:33 ` Tea
@ 2008-05-21 17:14 ` Tea
2008-05-21 22:01 ` Michael Snyder
2 siblings, 1 reply; 33+ messages in thread
From: Tea @ 2008-05-21 17:14 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Michael Snyder, gdb-patches
Hi Thiago,
>
> General comments:
>
> - I think it would be useful to put a limit on the amount of
> entries that are kept in the record list, to avoid having GDB use
> all of the machine's memory on a big program. A way to say "record the
> last 50k instructions" would be nice, IMHO. This would make it
> practical to use the functionality when debugging larger programs.
> But perhaps this should be left as an improvement for the future?
>
This idea is cool. I like it. I will try to add it to record. Thanks. :-)
> - A question: if you record changes, then reverse GDB through them but
> stop it half-way, and then set the direction (gear? :-) ) back to
> forward, GDB will just play back the changes it has recorded, and not
> continue the inferior until it reaches the end of the record list,
> right?
>
Yes, it's right.
> If so this means that if the user goes back a few insns, modifies a
> variable which is used in an if condition, the code will still appear
> to take the branch it took before. This is unintuitive and may lead
> the inferior to an undefined state, impossible to achieve by regular
> runs of the program. So I think GDB either needs to be put in a
> "read-only" mode where it refuses to change inferior memory and
> registers, or it needs to discard the records made after the point
> where the change in inferior state was made. What do you think?
>
I think this is a bug of record. I will fix it.
> - Before the patch is committed, the user manual needs to be updated to
> explain how to use this feature, and also talk about its limitations.
> It would be better to extend the GDB Internals document as well, to
> provide an outline on how reversible debugging is implemented, and
> what needs to be done to make it support a new platform. IMHO this can
> wait until more discussion goes into the feature, to avoid having to
> change the documentation later.
>
Doc is always a big hard job for programer. :-)
> - Also, before the patch is committed it needs to be refreshed to apply
> against CVS HEAD and not 6.8. Also, you can choose to do this closer
> to when the patch is committed to avoid having to re-refresh it in
> case CVS HEAD changes too much.
>
OK.
>
>> i386-linux-tdep.c | 2533 +++++++++++++++++++++++++++++++++++++++++++++++++
>> i386-tdep.c | 2769 +++++++++++++++++++++++++++++++++++++++++++++++++++---
>
> This feature increases the size of these files a great deal. They are
> currently 459 lines and 2561 lines respectively (as of GDB 6.8). Perhaps
> creating separate files for platform-specific record code makes things
> more manageable (e.g., i386-linux-rec.c and i386-rec.c)? I guess that's
> a question to the GDB maintainers.
"a question to the GDB maintainers." I like this idea. :-D
>
>> mips-tdep.c | 734 ++++++++++++++
>
> OTOH, mips-tdep.c has originally 6124 lines and this patch adds
> relatively little to that.
This is because MIPS instructions is more simple than I386
instructions. Deal with i386 instructions is not very easy. Sometime I
hate CISC arch. :-)
>
>> --- a/gdb/gdbarch.c
>> +++ b/gdb/gdbarch.c
>> @@ -230,6 +230,8 @@ struct gdbarch
>> gdbarch_core_read_description_ftype *core_read_description;
>> gdbarch_static_transform_name_ftype *static_transform_name;
>> int sofun_address_maybe_missing;
>> + gdbarch_record_ftype *record;
>> + gdbarch_record_dasm_ftype *record_dasm;
>> };
>>
>>
>> @@ -352,6 +354,8 @@ struct gdbarch startup_gdbarch =
>> 0, /* core_read_description */
>> 0, /* static_transform_name */
>> 0, /* sofun_address_maybe_missing */
>> + NULL,
>> + NULL,
>> /* startup_gdbarch() */
>> };
>
> There should be comments in the lines above mentioning what those NULLs
> are for (record and record_dasm), like in the other elements of the
> structure.
OK.
>
>> --- a/gdb/i386-linux-tdep.c
>> +++ b/gdb/i386-linux-tdep.c
>> @@ -35,6 +35,9 @@
>> #include "solib-svr4.h"
>> #include "symtab.h"
>>
>> +#include "record.h"
>> +#include <stdint.h>
>
> Can we just include <stdint.h> and not worry, now? I think so, but not
> sure.
>
> Also, record.h needs to be added to i386-linux-tdep.c's dependencies
> list in Makefile.in. Same applies to other files which include record.h.
OK.
>
>> + if (!need_dasm)
>> + {
>> + if (record_arch_list_add_reg (I386_EIP_REGNUM))
>> + {
>> + return (-1);
>> + }
>> + }
>> + if (record_arch_list_add_end (need_dasm))
>> + {
>> + return (-1);
>> + }
>
> Looking at i386_record, need_dasm is always zero so the variable can be
> removed, and the call to record_arch_list_add_reg above doens't need to
> be inside the if (!need_dasm).
>
OK. I will remove it.
>> + if (record_list && (record_list->next || gdb_is_reverse))
>> + {
>> + discard_cleanups (old_cleanups);
>> + record_wait_step = step;
>> + return;
>> + }
>
> I think it's better to have a comment above the if condition explaining
> what it means. If I understood things correctly, if the condition is
> true then GDB is not really executing the inferior but merely playing
> back the recorded states stored by the record functionality, right?
>
Yes, you are right.
And I will add comment there.
>> @@ -1026,10 +1047,18 @@ wait_for_inferior (int treat_exec_as_sig
>>
>> while (1)
>> {
>> - if (deprecated_target_wait_hook)
>> - ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
>> + if (record_list && (record_list->next || gdb_is_reverse))
>> + {
>> + ecs->ptid = record_wait (current_gdbarch, ecs->waiton_ptid, ecs->wp);
>> + }
>
> Same remark here, about having a comment explaining the if condition.
OK.
>
>> @@ -2004,10 +2033,19 @@ handle_inferior_event (struct execution_
>> SPARC. */
>>
>> if (stop_signal == TARGET_SIGNAL_TRAP)
>> - ecs->random_signal
>> - = !(bpstat_explains_signal (stop_bpstat)
>> - || stepping_over_breakpoint
>> - || (step_range_end && step_resume_breakpoint == NULL));
>> + {
>> + if (gdb_is_reverse || gdb_is_recording)
>> + {
>> + ecs->random_signal = 0;
>> + }
>> + else
>> + {
>> + ecs->random_signal
>> + = !(bpstat_explains_signal (stop_bpstat)
>> + || stepping_over_breakpoint
>> + || (step_range_end && step_resume_breakpoint == NULL));
>> + }
>> + }
>
> IMHO, it is clearer to just extend the expression for random_signal,
> rather than introduce a special case for reversible debugging. What
> about the following?
>
> - || (step_range_end && step_resume_breakpoint == NULL));
> + || (step_range_end && step_resume_breakpoint == NULL)
> + || gdb_is_reverse
> + || gdb_is_recording);
>
It is cool. I will use it. Thanks. :-)
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>
> In addition to the changes you made to Makefile.in, you need to add a
> record.o target listing the source and header files it depends on. See
> the other .o targets there for an example.
>
OK. I will deal with it.
>> +static void
>> +record_list_release (record_t * rec)
>> +{
>> + record_t *tmp;
>> +
>> + while (rec)
>> + {
>> + tmp = rec;
>> + rec = rec->prev;
>> + xfree (tmp);
>> + }
>> +}
>
> This function will leak memory. You also need to free rec->u.reg.val or
> rec->u.mem.val, depending on the type of the record.
>
I will fix it.
>> + rec = (record_t *) xmalloc (sizeof (record_t));
>> + if (!rec)
>> + {
>> + fprintf_unfiltered (gdb_stdlog, "record: alloc memory error.\n");
>> + return (-1);
>> + }
>
> xmalloc will make GDB exit if memory is exhausted, so there's no need to
> check the return value.
>
OK. I will remove it.
>> + else if (record_list->type == record_mem)
>> + {
>> + /* mem */
>> + gdb_byte mem[record_list->u.mem.len];
>
> Variable length array is a C99 construct. Currently GDB code needs to
> restrict itself to at most C90 features, so you will need to explicitly
> allocate memory here. If there are other places where this syntax is
> used, they need to be changed as well.
>
I will change it to alloc.
>> + //registers_changed ();
>
> The commented out call should be removed.
>
>> +void
>> +record_close (void)
>> +{
>> + gdb_is_recording = 0;
>> + gdb_is_reverse = 0;
>> + record_list_release (record_list);
>
> This function will leak memory if record_list doesn't point to the very
> end of the linked list. From what I understood of the code, record_close
> may be called when GDB is playing back the records, so record_list can
> be pointing at any element of the list.
>
I will fix it.
> --
> []'s
> Thiago Jung Bauermann
> Software Engineer
> IBM Linux Technology Center
>
>
Thanks for your mail. It really help me a lot. I will deal with most
of them in record 0.1.4 that will release in this or next week.
For some big job such as read-only mode and limit instruction number,
I will deal with them in record 0.1.5. How do you think about it.
Thanks,
teawater
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-20 18:51 ` Michael Snyder
@ 2008-05-21 17:26 ` Tea
0 siblings, 0 replies; 33+ messages in thread
From: Tea @ 2008-05-21 17:26 UTC (permalink / raw)
To: Michael Snyder; +Cc: drow, Thiago Jung Bauermann, gdb-patches
On Wed, May 21, 2008 at 1:40 AM, Michael Snyder <msnyder@specifix.com> wrote:
> On Tue, 2008-05-20 at 11:55 +0800, Tea wrote:
>> Agree with Daniel.
>> I think current way is better than include Linux kernel header files.
>>
>> To compile GDB with Linux KERNEL? I think it will make compile GDB not
>> very easy. If the Linux Kernel change. The user need re-compile the
>> GDB?
>> Or add Linux Kernel files to GDB directory? It looks not very
>> professional. And maybe will cause some copyright problem.
>>
>> And this types size will not change very continually. The GLIBC use it
>> too. The kernel more like add new types than change the old types.
>
> There is another possibility. You might build something
> resembling gdbserver, and put the record/playback functionality
> in there. Have gdb talk to it by the remote serial protocol
> (over a socket, of course).
>
> There is an old branch in the cvs repository where we have
> stashed away a version of gdb that has some extra "reverse"
> syntax in the remote protocol.
>
> This would have the advantage of a clear separation layer,
> so that gdb would not have to be "poluted" by foreign header
> files with different copyrights and licensing, plus keeping
> a big chunk of complex code separate from gdb itself.
>
> Plus, you could now reverse-debug from one host to another,
> even across different architectures.
>
> Just an idea...
>
> Michael
>
>
>
I will try to make all the part of record to be the part of GDB.
BTW, I received the ASSIGNMENT - GNU GDB from FSF in Monday and I had
signed it and send it back.
Make simulator reverse-run with itself is a cool idea. It will make
speed higher than before.
Thanks,
teawater
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-21 17:14 ` Tea
@ 2008-05-21 22:01 ` Michael Snyder
2008-05-21 22:16 ` Thiago Jung Bauermann
0 siblings, 1 reply; 33+ messages in thread
From: Michael Snyder @ 2008-05-21 22:01 UTC (permalink / raw)
To: Tea; +Cc: Thiago Jung Bauermann, gdb-patches
On Wed, 2008-05-21 at 16:54 +0800, Tea wrote:
>
> > - A question: if you record changes, then reverse GDB through them but
> > stop it half-way, and then set the direction (gear? :-) ) back to
> > forward, GDB will just play back the changes it has recorded, and not
> > continue the inferior until it reaches the end of the record list,
> > right?
> >
>
> Yes, it's right.
>
> > If so this means that if the user goes back a few insns, modifies a
> > variable which is used in an if condition, the code will still appear
> > to take the branch it took before. This is unintuitive and may lead
> > the inferior to an undefined state, impossible to achieve by regular
> > runs of the program. So I think GDB either needs to be put in a
> > "read-only" mode where it refuses to change inferior memory and
> > registers, or it needs to discard the records made after the point
> > where the change in inferior state was made. What do you think?
> >
> I think this is a bug of record. I will fix it.
Once you get into the idea of going backward, you soon reach
the idea of forking or branching -- taking a different route
forward than you did originally.
For an early implementation of reverse debugging, it would
be fair to simply prohibit this -- don't let gdb change the
machine state until you exit replay mode.
If you want to get fancier, you could say that if the user
does anything to change the recorded machine state, you
automatically cancel replay mode and resume debugging a "live"
machine from the new, changed state.
If you want to improve on that a little bit more, you might
say "If you change the machine state in the middle of a
replay, I will throw away all of the recorded state *forward*
of that point, but keep the recorded state going *back* from
there. You can't go back into what used to be the "future"
because by changing the past, you have now destroyed that
particular future. But you can still go further into the
past.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-21 22:01 ` Michael Snyder
@ 2008-05-21 22:16 ` Thiago Jung Bauermann
2008-05-21 22:40 ` Daniel Jacobowitz
0 siblings, 1 reply; 33+ messages in thread
From: Thiago Jung Bauermann @ 2008-05-21 22:16 UTC (permalink / raw)
To: Michael Snyder; +Cc: Tea, gdb-patches
On Wed, 2008-05-21 at 11:10 -0700, Michael Snyder wrote:
> If you want to improve on that a little bit more, you might
> say "If you change the machine state in the middle of a
> replay, I will throw away all of the recorded state *forward*
> of that point, but keep the recorded state going *back* from
> there. You can't go back into what used to be the "future"
> because by changing the past, you have now destroyed that
> particular future. But you can still go further into the
> past.
Right. And that's very easy to implement right? Just throw away the
recorded entries "in the future". Or am I being to naïve?
--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-21 22:16 ` Thiago Jung Bauermann
@ 2008-05-21 22:40 ` Daniel Jacobowitz
2008-05-22 15:08 ` Thiago Jung Bauermann
0 siblings, 1 reply; 33+ messages in thread
From: Daniel Jacobowitz @ 2008-05-21 22:40 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Michael Snyder, Tea, gdb-patches
On Wed, May 21, 2008 at 03:35:16PM -0300, Thiago Jung Bauermann wrote:
> On Wed, 2008-05-21 at 11:10 -0700, Michael Snyder wrote:
> > If you want to improve on that a little bit more, you might
> > say "If you change the machine state in the middle of a
> > replay, I will throw away all of the recorded state *forward*
> > of that point, but keep the recorded state going *back* from
> > there. You can't go back into what used to be the "future"
> > because by changing the past, you have now destroyed that
> > particular future. But you can still go further into the
> > past.
>
> Right. And that's very easy to implement right? Just throw away the
> recorded entries "in the future". Or am I being to naïve?
It depends... hey, weren't you at my talk about this last June? :-)
I don't remember if I went into this part but there's a section in the
proceedings. Continuing forward from a modified point depends on
being able to synchronize external and recorded state. Just
destroying the recorded state would work if you could detect
relevant modifications - it's made slightly tricky by memory
breakpoints but you're right, it's not too hard.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-21 22:40 ` Daniel Jacobowitz
@ 2008-05-22 15:08 ` Thiago Jung Bauermann
2008-05-23 2:54 ` Tea
0 siblings, 1 reply; 33+ messages in thread
From: Thiago Jung Bauermann @ 2008-05-22 15:08 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Michael Snyder, Tea, gdb-patches
On Wed, 2008-05-21 at 14:45 -0400, Daniel Jacobowitz wrote:
> On Wed, May 21, 2008 at 03:35:16PM -0300, Thiago Jung Bauermann wrote:
> > Right. And that's very easy to implement right? Just throw away the
> > recorded entries "in the future". Or am I being to naïve?
>
> It depends... hey, weren't you at my talk about this last June? :-)
Ahem. :-)
> I don't remember if I went into this part but there's a section in the
> proceedings.
IIRC, you did talk about the printf example and an event log.
> Continuing forward from a modified point depends on
> being able to synchronize external and recorded state. Just
> destroying the recorded state would work if you could detect
> relevant modifications - it's made slightly tricky by memory
> breakpoints but you're right, it's not too hard.
Yeah, I was ignoring the external world. Since the record patch also
ignores it, I guess it's okay for now...
That would probably be the meat of GDB record Mark II or something.
--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-22 15:08 ` Thiago Jung Bauermann
@ 2008-05-23 2:54 ` Tea
2008-05-23 4:33 ` Michael Snyder
0 siblings, 1 reply; 33+ messages in thread
From: Tea @ 2008-05-23 2:54 UTC (permalink / raw)
To: Thiago Jung Bauermann; +Cc: Daniel Jacobowitz, Michael Snyder, gdb-patches
I think the good way is let user choice. When the user goes back a few
insns and he want to change the values of memory or register. The GDB
willtalk clear what will happen such as the future record will
destory, and ask user if he want to continue or not.
Then user can choice with himself.
How do you think?
teawatert
On Thu, May 22, 2008 at 4:38 AM, Thiago Jung Bauermann
<bauerman@br.ibm.com> wrote:
> On Wed, 2008-05-21 at 14:45 -0400, Daniel Jacobowitz wrote:
>> On Wed, May 21, 2008 at 03:35:16PM -0300, Thiago Jung Bauermann wrote:
>> > Right. And that's very easy to implement right? Just throw away the
>> > recorded entries "in the future". Or am I being to naïve?
>>
>> It depends... hey, weren't you at my talk about this last June? :-)
>
> Ahem. :-)
>
>> I don't remember if I went into this part but there's a section in the
>> proceedings.
>
> IIRC, you did talk about the printf example and an event log.
>
>> Continuing forward from a modified point depends on
>> being able to synchronize external and recorded state. Just
>> destroying the recorded state would work if you could detect
>> relevant modifications - it's made slightly tricky by memory
>> breakpoints but you're right, it's not too hard.
>
> Yeah, I was ignoring the external world. Since the record patch also
> ignores it, I guess it's okay for now...
>
> That would probably be the meat of GDB record Mark II or something.
> --
> []'s
> Thiago Jung Bauermann
> Software Engineer
> IBM Linux Technology Center
>
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-04-23 8:55 GDB record patch 0.1.3.1 for GDB-6.8 release Tea
2008-05-20 4:33 ` Thiago Jung Bauermann
@ 2008-05-23 3:52 ` Pedro Alves
2008-05-23 14:31 ` Tea
1 sibling, 1 reply; 33+ messages in thread
From: Pedro Alves @ 2008-05-23 3:52 UTC (permalink / raw)
To: gdb-patches; +Cc: Tea, Michael Snyder, Thiago Jung Bauermann
Hi Teawater,
I took a really quick glimpse at the patch, and I was wondering if making the
record target a proper target that sits on top of all the other targets
wouldn't make more sense?
enum strata
{
dummy_stratum, /* The lowest of the low */
file_stratum, /* Executable files, etc */
core_stratum, /* Core dump files */
process_stratum, /* Executing processes */
thread_stratum, /* Executing threads */
record_stratum /* Support reverse debugging */
};
Then, things could be a bit more encapsulated. e.g., this wouldn't be needed,
@@ -1026,10 +1047,18 @@ wait_for_inferior (int treat_exec_as_sig
while (1)
{
- if (deprecated_target_wait_hook)
- ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
+ if (record_list && (record_list->next || gdb_is_reverse))
+ {
+ ecs->ptid = record_wait (current_gdbarch, ecs->waiton_ptid,
ecs->wp);
+ }
else
- ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+ {
+ if (deprecated_target_wait_hook)
+ ecs->ptid =
+ deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
+ else
+ ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
+ }
Those new checks could be done inside record_wait, and if eval as false,
defer to the target beneath.
There are probably other things that would become cleaner too.
--
Pedro Alves
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-23 2:54 ` Tea
@ 2008-05-23 4:33 ` Michael Snyder
2008-05-23 14:33 ` Tea
0 siblings, 1 reply; 33+ messages in thread
From: Michael Snyder @ 2008-05-23 4:33 UTC (permalink / raw)
To: Tea; +Cc: gdb-patches
On Fri, 2008-05-23 at 00:17 +0800, Tea wrote:
> I think the good way is let user choice. When the user goes back a few
> insns and he want to change the values of memory or register. The GDB
> willtalk clear what will happen such as the future record will
> destory, and ask user if he want to continue or not.
> Then user can choice with himself.
>
> How do you think?
I tend to agree about the user choice.
Perhaps we could have it as a user-settable mode.
Default might be "the past is read-only", ie. you
can't change the state. But you could set a mode
in which you can change the past (at the cost of
destroying the future) -- and if you try to do it
when the past is read-only, gdb could ask you if
you want to change the mode.
Is that clear? Or am I being too metaphorical?
Michael
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-23 3:52 ` Pedro Alves
@ 2008-05-23 14:31 ` Tea
2008-05-23 21:10 ` Pedro Alves
0 siblings, 1 reply; 33+ messages in thread
From: Tea @ 2008-05-23 14:31 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, Michael Snyder, Thiago Jung Bauermann
Hi Pedro,
At first, thanks for your mail.
On Fri, May 23, 2008 at 12:37 AM, Pedro Alves <pedro@codesourcery.com> wrote:
> Hi Teawater,
>
> I took a really quick glimpse at the patch, and I was wondering if making the
> record target a proper target that sits on top of all the other targets
> wouldn't make more sense?
>
> enum strata
> {
> dummy_stratum, /* The lowest of the low */
> file_stratum, /* Executable files, etc */
> core_stratum, /* Core dump files */
> process_stratum, /* Executing processes */
> thread_stratum, /* Executing threads */
>
> record_stratum /* Support reverse debugging */
> };
>
> Then, things could be a bit more encapsulated. e.g., this wouldn't be needed,
Sorry, I am not very clear this part of code. I tried, but ...
>
> @@ -1026,10 +1047,18 @@ wait_for_inferior (int treat_exec_as_sig
>
> while (1)
> {
> - if (deprecated_target_wait_hook)
> - ecs->ptid = deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
> + if (record_list && (record_list->next || gdb_is_reverse))
> + {
> + ecs->ptid = record_wait (current_gdbarch, ecs->waiton_ptid,
> ecs->wp);
> + }
> else
> - ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
> + {
> + if (deprecated_target_wait_hook)
> + ecs->ptid =
> + deprecated_target_wait_hook (ecs->waiton_ptid, ecs->wp);
> + else
> + ecs->ptid = target_wait (ecs->waiton_ptid, ecs->wp);
> + }
>
> Those new checks could be done inside record_wait, and if eval as false,
> defer to the target beneath.
I am not very clear your meaning. Could you please write a example for me?
Thanks,
teawater
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-23 4:33 ` Michael Snyder
@ 2008-05-23 14:33 ` Tea
2008-05-23 16:46 ` Michael Snyder
0 siblings, 1 reply; 33+ messages in thread
From: Tea @ 2008-05-23 14:33 UTC (permalink / raw)
To: Michael Snyder; +Cc: gdb-patches
Hi Michael,
How do you think about "query". I always forget the name of variable
that can set by user. So I more like query than it. :)
Thanks,
teawater
On Fri, May 23, 2008 at 2:15 AM, Michael Snyder <msnyder@specifix.com> wrote:
> On Fri, 2008-05-23 at 00:17 +0800, Tea wrote:
>> I think the good way is let user choice. When the user goes back a few
>> insns and he want to change the values of memory or register. The GDB
>> willtalk clear what will happen such as the future record will
>> destory, and ask user if he want to continue or not.
>> Then user can choice with himself.
>>
>> How do you think?
>
> I tend to agree about the user choice.
> Perhaps we could have it as a user-settable mode.
>
> Default might be "the past is read-only", ie. you
> can't change the state. But you could set a mode
> in which you can change the past (at the cost of
> destroying the future) -- and if you try to do it
> when the past is read-only, gdb could ask you if
> you want to change the mode.
>
> Is that clear? Or am I being too metaphorical?
>
> Michael
>
>
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-23 14:33 ` Tea
@ 2008-05-23 16:46 ` Michael Snyder
2008-05-23 18:16 ` Tea
0 siblings, 1 reply; 33+ messages in thread
From: Michael Snyder @ 2008-05-23 16:46 UTC (permalink / raw)
To: Tea; +Cc: gdb-patches
On Fri, 2008-05-23 at 11:04 +0800, Tea wrote:
> Hi Michael,
>
> How do you think about "query". I always forget the name of variable
> that can set by user. So I more like query than it. :)
Sorry, we have an existing set of commands, and we
like to stay consistent with those.
A user settable mode is set via the command "set".
Type "help set" and you'll see a large number of them.
They can have lots of different kinds of values, eg.
integers, strings, or small sets of enums like "on" and "off".
It's not difficult, I can point you to a few examples
of how it's done if you like.
Michael
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-23 16:46 ` Michael Snyder
@ 2008-05-23 18:16 ` Tea
0 siblings, 0 replies; 33+ messages in thread
From: Tea @ 2008-05-23 18:16 UTC (permalink / raw)
To: Michael Snyder; +Cc: gdb-patches
Maybe we can add both of them. In the default, GDB will call query to
ask user what he want, read only or set value and destroy the future.
And user can set GDB to always read only or always destroy. I think
it's friendly to the user.
teawater
On Fri, May 23, 2008 at 1:00 PM, Michael Snyder <msnyder@specifix.com> wrote:
> On Fri, 2008-05-23 at 11:04 +0800, Tea wrote:
>> Hi Michael,
>>
>> How do you think about "query". I always forget the name of variable
>> that can set by user. So I more like query than it. :)
>
> Sorry, we have an existing set of commands, and we
> like to stay consistent with those.
>
> A user settable mode is set via the command "set".
> Type "help set" and you'll see a large number of them.
> They can have lots of different kinds of values, eg.
> integers, strings, or small sets of enums like "on" and "off".
>
> It's not difficult, I can point you to a few examples
> of how it's done if you like.
>
> Michael
>
>
>
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-23 14:31 ` Tea
@ 2008-05-23 21:10 ` Pedro Alves
2008-06-08 6:53 ` teawater
0 siblings, 1 reply; 33+ messages in thread
From: Pedro Alves @ 2008-05-23 21:10 UTC (permalink / raw)
To: gdb-patches; +Cc: Tea, Michael Snyder, Thiago Jung Bauermann
A Friday 23 May 2008 03:54:06, Tea wrote:
> Hi Pedro,
> I am not very clear your meaning. Could you please write a example for me?
Sure, I'll try.
Think of the target stack roughly as polimorphism. Each layer
of the stack overrides methods of the layer beneath. A stratum
concept is used because there is a layering order on the stack, where
a given target implementation can sit at. E.g., a thread_stratum layer
target always sits above a process_stratum layer target. The
file_stratum is always below the process_stratum. When core GDB wants
to wait for a debug event, it calls target_wait. E.g, on linux native
debugging, that ends up calling linux_nat_wait on non multi-threaded
applications. If your new target is the topmost on the stack, then
record_wait would be called instead.
There's some description of it in the gdbint manual in
the "Target Vector Definition" node, but it isn't much complete.
There are more comments describing the struture in target.h.
As I said, if you make "record" sit on the target vector, then a
call to target_wait (), would really be calling record_wait (),
e.g.,
ptid_t
record_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
{
if (record_list && (record_list->next || gdb_is_reverse)))
{
... do whatever you were doing in record_wait ...
}
else
return t->beneath->to_wait (ptid, outstatus);
}
Same for target_mourn_inferior, and target_close, at least.
See remote.c:init_remote_ops, and any struct target_ops
instance in GDB (like remote_ops in remote.c) for examples,
or perhaps a more staightforward one as win32-nat.c:win32_ops.
Issuing the "record" command would push the record target on
the stack, and stoprecord would pop it, and normally
target_mourn_inferior and target_detach do it too, although you
probably want to be able to shift to reverse after a
process death. The new stratum suggestion was so it always sits
above all the others (see target.c:push_target)
record_ops.to_stratum = above_all_or_whatever_new_stratum;
record_ops.to_wait = record_wait;
/* record resume would be were you call record_message. */
record_ops.to_resume = record_resume;
/* Calls record_close, and pops target record off the stack. */
record_ops.to_mourn_inferior = record_mourn_inferior;
etc.
At a first glimpse it looks desirable to go this path.
You may get around to even abstract more things that you're doing
in infrun.c. Take this only as an investigation suggestion.
--
Pedro Alves
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-05-23 21:10 ` Pedro Alves
@ 2008-06-08 6:53 ` teawater
2008-06-09 0:52 ` Pedro Alves
0 siblings, 1 reply; 33+ messages in thread
From: teawater @ 2008-06-08 6:53 UTC (permalink / raw)
To: Pedro Alves, gdb-patches; +Cc: Michael Snyder, Thiago Jung Bauermann
Cool. This idea is so cool.
In before, I tried to make clear about the "strata", but I gave up.
Now, I know this thing is so cool.
But it let me very puzzled that which way is the best.
The way that I used in before, I have done a a lot of things on it.
And it can be used.
The way that use a special target for record, I think this way look
professional.
Please tell me your idea about it. Thanks a lot.
BTW, I realse record 0.1.4 and 0.1.5. Please give me you advice about it.
http://sourceware.org/ml/gdb-patches/2008-05/msg00692.html
http://sourceware.org/ml/gdb-patches/2008-06/msg00041.html
Thanks,
teawater
On Sat, May 24, 2008 at 00:46, Pedro Alves <pedro@codesourcery.com> wrote:
>
> A Friday 23 May 2008 03:54:06, Tea wrote:
> > Hi Pedro,
> > I am not very clear your meaning. Could you please write a example for me?
>
> Sure, I'll try.
>
> Think of the target stack roughly as polimorphism. Each layer
> of the stack overrides methods of the layer beneath. A stratum
> concept is used because there is a layering order on the stack, where
> a given target implementation can sit at. E.g., a thread_stratum layer
> target always sits above a process_stratum layer target. The
> file_stratum is always below the process_stratum. When core GDB wants
> to wait for a debug event, it calls target_wait. E.g, on linux native
> debugging, that ends up calling linux_nat_wait on non multi-threaded
> applications. If your new target is the topmost on the stack, then
> record_wait would be called instead.
>
> There's some description of it in the gdbint manual in
> the "Target Vector Definition" node, but it isn't much complete.
> There are more comments describing the struture in target.h.
>
> As I said, if you make "record" sit on the target vector, then a
> call to target_wait (), would really be calling record_wait (),
> e.g.,
>
> ptid_t
> record_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
> {
> if (record_list && (record_list->next || gdb_is_reverse)))
> {
> ... do whatever you were doing in record_wait ...
> }
> else
> return t->beneath->to_wait (ptid, outstatus);
> }
>
> Same for target_mourn_inferior, and target_close, at least.
>
> See remote.c:init_remote_ops, and any struct target_ops
> instance in GDB (like remote_ops in remote.c) for examples,
> or perhaps a more staightforward one as win32-nat.c:win32_ops.
>
> Issuing the "record" command would push the record target on
> the stack, and stoprecord would pop it, and normally
> target_mourn_inferior and target_detach do it too, although you
> probably want to be able to shift to reverse after a
> process death. The new stratum suggestion was so it always sits
> above all the others (see target.c:push_target)
>
> record_ops.to_stratum = above_all_or_whatever_new_stratum;
> record_ops.to_wait = record_wait;
>
> /* record resume would be were you call record_message. */
> record_ops.to_resume = record_resume;
>
> /* Calls record_close, and pops target record off the stack. */
> record_ops.to_mourn_inferior = record_mourn_inferior;
>
> etc.
>
> At a first glimpse it looks desirable to go this path.
> You may get around to even abstract more things that you're doing
> in infrun.c. Take this only as an investigation suggestion.
>
> --
> Pedro Alves
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-08 6:53 ` teawater
@ 2008-06-09 0:52 ` Pedro Alves
2008-06-09 3:00 ` Daniel Jacobowitz
2008-06-11 11:59 ` teawater
0 siblings, 2 replies; 33+ messages in thread
From: Pedro Alves @ 2008-06-09 0:52 UTC (permalink / raw)
To: teawater; +Cc: gdb-patches, Michael Snyder, Thiago Jung Bauermann
A Sunday 08 June 2008 07:53:14, teawater wrote:
> Cool. This idea is so cool.
> In before, I tried to make clear about the "strata", but I gave up.
> Now, I know this thing is so cool.
> But it let me very puzzled that which way is the best.
> The way that I used in before, I have done a a lot of things on it.
Don't worry, it's really more about code reorganization, than
rewriting. :-)
You have two major components in your patch.
1 - The record/replay component
2 - The inferior control in reverse execution mode.
I'm suggesting to split those up, and make them communicate
with an abstracted interface (target methods). In addition,
make the record support a layer on top of the
forward-execution-only debugging targets (of course, defering
much to the arch support).
> And it can be used.
> The way that use a special target for record, I think this way look
> professional.
> Please tell me your idea about it. Thanks a lot.
My idea is that support for reverse execution should be exposed by
target methods and properties. Say target_can_reverse_p (),
target_set_execution_direction (...) or similar. For native
debugging, it might be possible to share most of the code
between similar targets.
So, in a native linux debugging session, with record activated, the
target stack would look this (ignoring the thread layer), top to
bottom:
target | stratum | supports reverse | Notes
-------------+------------------+--------------------+-------------
record | record_statum | 1 | (1)
linux native | process_stratum | 0 | -
exec target | file_stratum) | 0 | -
(1) encapsulates the recording and replaying of events.
Since record is on top, it answers the calls to target_can_reverse_p,
target_wait, etc.
In a remote debugging session, where the remote side does not support
recording, it should be possible to do the recording in the GDB side:
target | stratum | supports reverse | Notes
-------------+------------------+--------------------+-------------
record | record_statum | 1 | -
remote | process_stratum | 0 | (2)
exec target | file_stratum) | 0 | -
(2) - GDB claims support for remote protocol reverse debugging
extensions, but the remote side didn't support them.
E.g.: Connect to an x86-linux gdbserver, and support reverse
execution the same way you support recording native debugging.
E.g., you may need to force single-stepping in
record_resume, even if the upper layer didn't request it, I'd
leave that to you :-)
target | stratum | supports reverse | Notes
-------------+------------------+--------------------+-------------
remote | process_stratum | 1 | (3)
exec target | file_stratum) | 0 | -
(3) - GDB claims support for remote protocol reverse
debugging extensions, and the remote side also claimed support.
This would be the prefered method to support reverse execution
when GDB is connected to a simulator or emulator. GDB would
tell the remote "reverse step", and the remote end would
take care of the reverse replaying.
Another alternative, is to fold the record support
into the process_stratum layer, but it doesn't look as
clean:
target | stratum | supports reverse | Notes
-------------+------------------+--------------------+-------------
linux native | process_stratum | 1 | (4)
exec target | file_stratum) | 0 | -
(4) Manages the recording and replaying itself, by defering
to the record component.
I'd prefer the separation into a new layer if it is possible
at all.
This imposes a requirement that the common code doesn't
know about the record target's internals, but instead relies on
target methods and properties. E.g. in infrun.c, instead of
checking your record variables directly, you'd check for
say, target_execution_direction () == EXEC_DIRECTION_REVERSE.
I have no idea how feasible is this. This is just my
gut feeling about it. As I said, take this as an investigation
suggestion. :-)
What do others think?
--
Pedro Alves
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-09 0:52 ` Pedro Alves
@ 2008-06-09 3:00 ` Daniel Jacobowitz
2008-06-09 13:58 ` Thiago Jung Bauermann
2008-06-09 22:56 ` Michael Snyder
2008-06-11 11:59 ` teawater
1 sibling, 2 replies; 33+ messages in thread
From: Daniel Jacobowitz @ 2008-06-09 3:00 UTC (permalink / raw)
To: Pedro Alves; +Cc: teawater, gdb-patches, Michael Snyder, Thiago Jung Bauermann
On Mon, Jun 09, 2008 at 01:51:59AM +0100, Pedro Alves wrote:
> My idea is that support for reverse execution should be exposed by
> target methods and properties. Say target_can_reverse_p (),
> target_set_execution_direction (...) or similar. For native
> debugging, it might be possible to share most of the code
> between similar targets.
I want to make sure everyone realizes that patches for this have
already been posted, by Michael Snyder. It was a while ago so it may
have fallen out of our institutional memory :-) I recently sent
Michael an updated version of his patches, off list.
Perhaps we can get those in, providing the abstract methods and remote
protocol support, and then see what parts of the record patch it
simplifies?
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-09 3:00 ` Daniel Jacobowitz
@ 2008-06-09 13:58 ` Thiago Jung Bauermann
2008-06-10 2:04 ` Michael Snyder
2008-06-09 22:56 ` Michael Snyder
1 sibling, 1 reply; 33+ messages in thread
From: Thiago Jung Bauermann @ 2008-06-09 13:58 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, teawater, gdb-patches, Michael Snyder
On Sun, 2008-06-08 at 22:59 -0400, Daniel Jacobowitz wrote:
> I want to make sure everyone realizes that patches for this have
> already been posted, by Michael Snyder. It was a while ago so it may
> have fallen out of our institutional memory :-) I recently sent
> Michael an updated version of his patches, off list.
Could you send them to me as well?
--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-09 3:00 ` Daniel Jacobowitz
2008-06-09 13:58 ` Thiago Jung Bauermann
@ 2008-06-09 22:56 ` Michael Snyder
1 sibling, 0 replies; 33+ messages in thread
From: Michael Snyder @ 2008-06-09 22:56 UTC (permalink / raw)
To: Daniel Jacobowitz
Cc: Pedro Alves, teawater, gdb-patches, Thiago Jung Bauermann
On Sun, 2008-06-08 at 22:59 -0400, Daniel Jacobowitz wrote:
> On Mon, Jun 09, 2008 at 01:51:59AM +0100, Pedro Alves wrote:
> > My idea is that support for reverse execution should be exposed by
> > target methods and properties. Say target_can_reverse_p (),
> > target_set_execution_direction (...) or similar. For native
> > debugging, it might be possible to share most of the code
> > between similar targets.
>
> I want to make sure everyone realizes that patches for this have
> already been posted, by Michael Snyder. It was a while ago so it may
> have fallen out of our institutional memory :-) I recently sent
> Michael an updated version of his patches, off list.
>
> Perhaps we can get those in, providing the abstract methods and remote
> protocol support, and then see what parts of the record patch it
> simplifies?
I also want to do this. I will begin looking into, at the least,
creating a revised patch branch that brings the existing patches
up to date. Then we can discuss importing them into the main
trunk.
I am sure that the gdb record patch will benefit.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-09 13:58 ` Thiago Jung Bauermann
@ 2008-06-10 2:04 ` Michael Snyder
0 siblings, 0 replies; 33+ messages in thread
From: Michael Snyder @ 2008-06-10 2:04 UTC (permalink / raw)
To: Thiago Jung Bauermann
Cc: Daniel Jacobowitz, Pedro Alves, teawater, gdb-patches
On Mon, 2008-06-09 at 10:47 -0300, Thiago Jung Bauermann wrote:
> On Sun, 2008-06-08 at 22:59 -0400, Daniel Jacobowitz wrote:
> > I want to make sure everyone realizes that patches for this have
> > already been posted, by Michael Snyder. It was a while ago so it may
> > have fallen out of our institutional memory :-) I recently sent
> > Michael an updated version of his patches, off list.
>
> Could you send them to me as well?
So I've created a new branch, incorporating Daniel's patch set.
The new branch forks from the main trunk at 2007-04-07,
and is therefore about a year more up to date (and several
releases newer) than the previous branch. It is, however,
completely untested at this point, so use at your own risk.
Branch name -- drow-reverse-20070409-branch
I will be working on creating a newer branch based on todays tree,
with the eventual goal of integrating it into the trunk.
Michael
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-09 0:52 ` Pedro Alves
2008-06-09 3:00 ` Daniel Jacobowitz
@ 2008-06-11 11:59 ` teawater
2008-06-11 20:03 ` Michael Snyder
1 sibling, 1 reply; 33+ messages in thread
From: teawater @ 2008-06-11 11:59 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, Michael Snyder, Thiago Jung Bauermann
Hi Pedro,
> Don't worry, it's really more about code reorganization, than
> rewriting. :-)
>
> You have two major components in your patch.
>
> 1 - The record/replay component
> 2 - The inferior control in reverse execution mode.
>
> I'm suggesting to split those up, and make them communicate
> with an abstracted interface (target methods). In addition,
> make the record support a layer on top of the
> forward-execution-only debugging targets (of course, defering
> much to the arch support).
>
Michael Snyder is think about it too. He make a rev interface in
before. I will try to use it.
> My idea is that support for reverse execution should be exposed by
> target methods and properties. Say target_can_reverse_p (),
> target_set_execution_direction (...) or similar. For native
> debugging, it might be possible to share most of the code
> between similar targets.
>
> So, in a native linux debugging session, with record activated, the
> target stack would look this (ignoring the thread layer), top to
> bottom:
>
> target | stratum | supports reverse | Notes
> -------------+------------------+--------------------+-------------
> record | record_statum | 1 | (1)
> linux native | process_stratum | 0 | -
> exec target | file_stratum) | 0 | -
>
It's cool. But record only need the support of memory control and
register control from target. So I think most of target can support
record.
For the speed up, I change the code of Linux-Nat. But other target
such as "remote" still support by record.
The record need most support is from GDBARCH. It need add a function
like disassemble function in GDBARCH.
I think make record to be a target is very cool idea. But to implement
the current record. I have already changed a lot of code in GDB core
part. After I make record to a target, I think it maybe will still
have a lot of code in GDB core part. So make it to be a target is very
important?
Thanks,
Hui
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-11 11:59 ` teawater
@ 2008-06-11 20:03 ` Michael Snyder
2008-06-12 18:10 ` teawater
0 siblings, 1 reply; 33+ messages in thread
From: Michael Snyder @ 2008-06-11 20:03 UTC (permalink / raw)
To: teawater; +Cc: Pedro Alves, gdb-patches, Thiago Jung Bauermann
On Wed, 2008-06-11 at 15:45 +0800, teawater wrote:
> Hi Pedro,
>
> > Don't worry, it's really more about code reorganization, than
> > rewriting. :-)
> >
> > You have two major components in your patch.
> >
> > 1 - The record/replay component
> > 2 - The inferior control in reverse execution mode.
> >
> > I'm suggesting to split those up, and make them communicate
> > with an abstracted interface (target methods). In addition,
> > make the record support a layer on top of the
> > forward-execution-only debugging targets (of course, defering
> > much to the arch support).
> >
> Michael Snyder is think about it too. He make a rev interface in
> before. I will try to use it.
Hui,
I've created a new branch in which I've hoisted my old
reverse-debugging changes into the current codebase.
It compiles, but I haven't had a chance to test it yet
to see if it actually works in reverse.
You might like to take a look at it, to get an idea of
the direction we were most recently headed -- maybe diff
it against the base to look at the changes.
Branch name: msnyder-reverse-20080609-branch
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-11 20:03 ` Michael Snyder
@ 2008-06-12 18:10 ` teawater
2008-06-13 6:08 ` Michael Snyder
0 siblings, 1 reply; 33+ messages in thread
From: teawater @ 2008-06-12 18:10 UTC (permalink / raw)
To: Michael Snyder; +Cc: Pedro Alves, gdb-patches, Thiago Jung Bauermann
Thanks Michael,
I've got it and read it. :)
Hui
On Thu, Jun 12, 2008 at 01:11, Michael Snyder <msnyder@specifix.com> wrote:
> On Wed, 2008-06-11 at 15:45 +0800, teawater wrote:
>> Hi Pedro,
>>
>> > Don't worry, it's really more about code reorganization, than
>> > rewriting. :-)
>> >
>> > You have two major components in your patch.
>> >
>> > 1 - The record/replay component
>> > 2 - The inferior control in reverse execution mode.
>> >
>> > I'm suggesting to split those up, and make them communicate
>> > with an abstracted interface (target methods). In addition,
>> > make the record support a layer on top of the
>> > forward-execution-only debugging targets (of course, defering
>> > much to the arch support).
>> >
>> Michael Snyder is think about it too. He make a rev interface in
>> before. I will try to use it.
>
> Hui,
>
> I've created a new branch in which I've hoisted my old
> reverse-debugging changes into the current codebase.
> It compiles, but I haven't had a chance to test it yet
> to see if it actually works in reverse.
>
> You might like to take a look at it, to get an idea of
> the direction we were most recently headed -- maybe diff
> it against the base to look at the changes.
>
> Branch name: msnyder-reverse-20080609-branch
>
>
>
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-12 18:10 ` teawater
@ 2008-06-13 6:08 ` Michael Snyder
2008-06-14 6:24 ` teawater
0 siblings, 1 reply; 33+ messages in thread
From: Michael Snyder @ 2008-06-13 6:08 UTC (permalink / raw)
To: teawater; +Cc: Pedro Alves, gdb-patches, Thiago Jung Bauermann
Good --- making some good progress toward testing it.
At a fairly basic level, it seems to work, but there
may have been a little bit-rot around the most tricky
bits (stepping backward in and out of functions, that
sort of thing).
Hui, you might look at isolating just the
"set exec-direction" part and the target bits.
Those might integrate well with what you are doing.
On Thu, 2008-06-12 at 13:50 +0800, teawater wrote:
> Thanks Michael,
>
> I've got it and read it. :)
>
> Hui
>
> On Thu, Jun 12, 2008 at 01:11, Michael Snyder <msnyder@specifix.com> wrote:
> > On Wed, 2008-06-11 at 15:45 +0800, teawater wrote:
> >> Hi Pedro,
> >>
> >> > Don't worry, it's really more about code reorganization, than
> >> > rewriting. :-)
> >> >
> >> > You have two major components in your patch.
> >> >
> >> > 1 - The record/replay component
> >> > 2 - The inferior control in reverse execution mode.
> >> >
> >> > I'm suggesting to split those up, and make them communicate
> >> > with an abstracted interface (target methods). In addition,
> >> > make the record support a layer on top of the
> >> > forward-execution-only debugging targets (of course, defering
> >> > much to the arch support).
> >> >
> >> Michael Snyder is think about it too. He make a rev interface in
> >> before. I will try to use it.
> >
> > Hui,
> >
> > I've created a new branch in which I've hoisted my old
> > reverse-debugging changes into the current codebase.
> > It compiles, but I haven't had a chance to test it yet
> > to see if it actually works in reverse.
> >
> > You might like to take a look at it, to get an idea of
> > the direction we were most recently headed -- maybe diff
> > it against the base to look at the changes.
> >
> > Branch name: msnyder-reverse-20080609-branch
> >
> >
> >
> >
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-13 6:08 ` Michael Snyder
@ 2008-06-14 6:24 ` teawater
2008-06-14 10:31 ` Michael Snyder
0 siblings, 1 reply; 33+ messages in thread
From: teawater @ 2008-06-14 6:24 UTC (permalink / raw)
To: Michael Snyder; +Cc: gdb-patches, Thiago Jung Bauermann, Pedro Alves
Hi Michael,
I am reading "msnyder-reverse-20080609-branch".
I want to say that it's so great. It make all the reverse function
very clear. I like it. :)
And I want say thanks to Pedro. Your idea that make recrd to be a
target is very fit "msnyder-reverse-20080609-branch".
To make record work with "msnyder-reverse-20080609-branch" without
your idea is so hard. :)
I want to make record to be a target how do you think about it?
Thanks,
teawater
On Fri, Jun 13, 2008 at 02:29, Michael Snyder <msnyder@specifix.com> wrote:
> Good --- making some good progress toward testing it.
> At a fairly basic level, it seems to work, but there
> may have been a little bit-rot around the most tricky
> bits (stepping backward in and out of functions, that
> sort of thing).
>
> Hui, you might look at isolating just the
> "set exec-direction" part and the target bits.
> Those might integrate well with what you are doing.
>
> On Thu, 2008-06-12 at 13:50 +0800, teawater wrote:
>> Thanks Michael,
>>
>> I've got it and read it. :)
>>
>> Hui
>>
>> On Thu, Jun 12, 2008 at 01:11, Michael Snyder <msnyder@specifix.com> wrote:
>> > On Wed, 2008-06-11 at 15:45 +0800, teawater wrote:
>> >> Hi Pedro,
>> >>
>> >> > Don't worry, it's really more about code reorganization, than
>> >> > rewriting. :-)
>> >> >
>> >> > You have two major components in your patch.
>> >> >
>> >> > 1 - The record/replay component
>> >> > 2 - The inferior control in reverse execution mode.
>> >> >
>> >> > I'm suggesting to split those up, and make them communicate
>> >> > with an abstracted interface (target methods). In addition,
>> >> > make the record support a layer on top of the
>> >> > forward-execution-only debugging targets (of course, defering
>> >> > much to the arch support).
>> >> >
>> >> Michael Snyder is think about it too. He make a rev interface in
>> >> before. I will try to use it.
>> >
>> > Hui,
>> >
>> > I've created a new branch in which I've hoisted my old
>> > reverse-debugging changes into the current codebase.
>> > It compiles, but I haven't had a chance to test it yet
>> > to see if it actually works in reverse.
>> >
>> > You might like to take a look at it, to get an idea of
>> > the direction we were most recently headed -- maybe diff
>> > it against the base to look at the changes.
>> >
>> > Branch name: msnyder-reverse-20080609-branch
>> >
>> >
>> >
>> >
>
>
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-14 6:24 ` teawater
@ 2008-06-14 10:31 ` Michael Snyder
2008-06-15 3:27 ` teawater
0 siblings, 1 reply; 33+ messages in thread
From: Michael Snyder @ 2008-06-14 10:31 UTC (permalink / raw)
To: teawater; +Cc: gdb-patches, Thiago Jung Bauermann, Pedro Alves
On Sat, 2008-06-14 at 11:19 +0800, teawater wrote:
> Hi Michael,
>
> I am reading "msnyder-reverse-20080609-branch".
> I want to say that it's so great. It make all the reverse function
> very clear. I like it. :)
>
> And I want say thanks to Pedro. Your idea that make recrd to be a
> target is very fit "msnyder-reverse-20080609-branch".
> To make record work with "msnyder-reverse-20080609-branch" without
> your idea is so hard. :)
>
> I want to make record to be a target how do you think about it?
I think it makes sense.
It's a good way to keep things isolated from each other.
It should make it possible to say "look, this can't possibly
break anything else", which will hasten acceptance.
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: GDB record patch 0.1.3.1 for GDB-6.8 release
2008-06-14 10:31 ` Michael Snyder
@ 2008-06-15 3:27 ` teawater
0 siblings, 0 replies; 33+ messages in thread
From: teawater @ 2008-06-15 3:27 UTC (permalink / raw)
To: Michael Snyder; +Cc: gdb-patches, Thiago Jung Bauermann, Pedro Alves
On Sat, Jun 14, 2008 at 12:59, Michael Snyder <msnyder@specifix.com> wrote:
> On Sat, 2008-06-14 at 11:19 +0800, teawater wrote:
>> Hi Michael,
>>
>> I am reading "msnyder-reverse-20080609-branch".
>> I want to say that it's so great. It make all the reverse function
>> very clear. I like it. :)
>>
>> And I want say thanks to Pedro. Your idea that make recrd to be a
>> target is very fit "msnyder-reverse-20080609-branch".
>> To make record work with "msnyder-reverse-20080609-branch" without
>> your idea is so hard. :)
>>
>> I want to make record to be a target how do you think about it?
>
> I think it makes sense.
> It's a good way to keep things isolated from each other.
>
> It should make it possible to say "look, this can't possibly
> break anything else", which will hasten acceptance.
>
OK. :)
^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2008-06-15 0:44 UTC | newest]
Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-04-23 8:55 GDB record patch 0.1.3.1 for GDB-6.8 release Tea
2008-05-20 4:33 ` Thiago Jung Bauermann
2008-05-20 6:38 ` Daniel Jacobowitz
2008-05-20 15:32 ` Tea
2008-05-20 18:51 ` Michael Snyder
2008-05-21 17:26 ` Tea
2008-05-20 15:33 ` Tea
2008-05-21 17:14 ` Tea
2008-05-21 22:01 ` Michael Snyder
2008-05-21 22:16 ` Thiago Jung Bauermann
2008-05-21 22:40 ` Daniel Jacobowitz
2008-05-22 15:08 ` Thiago Jung Bauermann
2008-05-23 2:54 ` Tea
2008-05-23 4:33 ` Michael Snyder
2008-05-23 14:33 ` Tea
2008-05-23 16:46 ` Michael Snyder
2008-05-23 18:16 ` Tea
2008-05-23 3:52 ` Pedro Alves
2008-05-23 14:31 ` Tea
2008-05-23 21:10 ` Pedro Alves
2008-06-08 6:53 ` teawater
2008-06-09 0:52 ` Pedro Alves
2008-06-09 3:00 ` Daniel Jacobowitz
2008-06-09 13:58 ` Thiago Jung Bauermann
2008-06-10 2:04 ` Michael Snyder
2008-06-09 22:56 ` Michael Snyder
2008-06-11 11:59 ` teawater
2008-06-11 20:03 ` Michael Snyder
2008-06-12 18:10 ` teawater
2008-06-13 6:08 ` Michael Snyder
2008-06-14 6:24 ` teawater
2008-06-14 10:31 ` Michael Snyder
2008-06-15 3:27 ` teawater
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox