diff -ruNa --exclude=CVS gdb-6.6/gdb/gdbarch.c gdb-6.6-record/gdb/gdbarch.c
--- gdb-6.6/gdb/gdbarch.c	2006-11-11 03:20:35.000000000 +0800
+++ gdb-6.6-record/gdb/gdbarch.c	2007-10-10 10:48:10.000000000 +0800
@@ -234,6 +234,10 @@
   gdbarch_register_reggroup_p_ftype *register_reggroup_p;
   gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
   gdbarch_regset_from_core_section_ftype *regset_from_core_section;
+/*teawater rec begin----------------------------------------------------------*/
+	gdbarch_record_ftype		*record;
+	gdbarch_record_dasm_ftype	*record_dasm;
+/*teawater rec end------------------------------------------------------------*/
 };
 
 
@@ -359,6 +363,10 @@
   default_register_reggroup_p,  /* register_reggroup_p */
   0,  /* fetch_pointer_argument */
   0,  /* regset_from_core_section */
+/*teawater rec begin----------------------------------------------------------*/
+  NULL,
+  NULL,
+/*teawater rec end------------------------------------------------------------*/
   /* startup_gdbarch() */
 };
 
@@ -4154,6 +4162,47 @@
   flush_cached_frames ();
 }
 
+/*teawater rec begin----------------------------------------------------------*/
+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 ());
+}
+
+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 ();
+}
+
+void
+set_gdbarch_record_dasm (struct gdbarch *gdbarch, gdbarch_record_dasm_ftype *record_dasm)
+{
+	gdbarch->record_dasm = record_dasm;
+}
+/*teawater rec end------------------------------------------------------------*/
+
 extern void _initialize_gdbarch (void);
 
 void
diff -ruNa --exclude=CVS gdb-6.6/gdb/gdbarch.h gdb-6.6-record/gdb/gdbarch.h
--- gdb-6.6/gdb/gdbarch.h	2006-11-11 03:20:36.000000000 +0800
+++ gdb-6.6-record/gdb/gdbarch.h	2007-10-10 10:53:36.000000000 +0800
@@ -1612,4 +1612,14 @@
 
 extern void gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file);
 
+/*teawater rec begin----------------------------------------------------------*/
+extern int	gdbarch_record_p (struct gdbarch *gdbarch);
+typedef int	(gdbarch_record_ftype) (void);
+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) (void);
+extern void	gdbarch_record_dasm (struct gdbarch *gdbarch);
+extern void	set_gdbarch_record_dasm (struct gdbarch *gdbarch, gdbarch_record_dasm_ftype *record_dasm);
+/*teawater rec end------------------------------------------------------------*/
+
 #endif
diff -ruNa --exclude=CVS gdb-6.6/gdb/infrun.c gdb-6.6-record/gdb/infrun.c
--- gdb-6.6/gdb/infrun.c	2006-10-19 00:56:13.000000000 +0800
+++ gdb-6.6-record/gdb/infrun.c	2007-10-11 16:36:41.000000000 +0800
@@ -52,6 +52,11 @@
 #include "gdb_assert.h"
 #include "mi/mi-common.h"
 
+/*teawater rec begin----------------------------------------------------------*/
+#include "record.h"
+static int		record_resume_step = 0;
+/*teawater rec end------------------------------------------------------------*/
+
 /* Prototypes for local functions */
 
 static void signals_info (char *, int);
@@ -532,6 +537,20 @@
     fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%d, signal=%d)\n",
 			step, sig);
 
+/*teawater rec begin----------------------------------------------------------*/
+	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 ();
+		}
+	}
+/*teawater rec end------------------------------------------------------------*/
+
   /* FIXME: calling breakpoint_here_p (read_pc ()) three times! */
 
 
@@ -1000,10 +1019,19 @@
 
   while (1)
     {
+/*teawater rec begin----------------------------------------------------------*/
+	if (record_list && (record_list->next || gdb_is_reverse)) {
+		ecs->ptid = record_wait (ecs->waiton_ptid, ecs->wp);
+	}
+	else {
+/*teawater rec end------------------------------------------------------------*/
       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);
+/*teawater rec begin----------------------------------------------------------*/
+	}
+/*teawater rec end------------------------------------------------------------*/
 
       /* Now figure out what to do with the result of the result.  */
       handle_inferior_event (ecs);
@@ -1916,11 +1944,19 @@
          be necessary for call dummies on a non-executable stack on
          SPARC.  */
 
-      if (stop_signal == TARGET_SIGNAL_TRAP)
-	ecs->random_signal
-	  = !(bpstat_explains_signal (stop_bpstat)
-	      || trap_expected
-	      || (step_range_end && step_resume_breakpoint == NULL));
+/*teawater rec begin----------------------------------------------------------*/
+      if (stop_signal == TARGET_SIGNAL_TRAP) {
+		if (gdb_is_reverse || gdb_is_recording) {
+			ecs->random_signal = 0;
+		}
+		else {
+			ecs->random_signal
+			  = !(bpstat_explains_signal (stop_bpstat)
+			      || trap_expected
+			      || (step_range_end && step_resume_breakpoint == NULL));
+		}
+	}
+/*teawater rec end------------------------------------------------------------*/
       else
 	{
 	  ecs->random_signal = !bpstat_explains_signal (stop_bpstat);
@@ -2424,6 +2460,16 @@
 	  /* We're doing a "next", set a breakpoint at callee's return
 	     address (the address at which the caller will
 	     resume).  */
+
+/*teawater rec begin----------------------------------------------------------*/
+		if (gdb_is_reverse || gdb_is_recording) {
+			record_resume_step = 1;
+			keep_going (ecs);
+			record_resume_step = 0;
+			return;
+		}
+/*teawater rec end------------------------------------------------------------*/
+
 	  insert_step_resume_breakpoint_at_caller (get_current_frame ());
 	  keep_going (ecs);
 	  return;
@@ -2485,6 +2531,15 @@
 	  return;
 	}
 
+/*teawater rec begin----------------------------------------------------------*/
+	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;
+	}
+/*teawater rec end------------------------------------------------------------*/
+
       /* 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 ());
@@ -2526,6 +2581,19 @@
 
   ecs->sal = find_pc_line (stop_pc, 0);
 
+/*teawater rec begin----------------------------------------------------------*/
+	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;
+		}
+	}
+/*teawater rec end------------------------------------------------------------*/
+
   /* NOTE: tausq/2004-05-24: This if block used to be done before all
      the trampoline processing logic, however, there are some trampolines 
      that have no names, so we should do trampoline handling first.  */
@@ -2536,6 +2604,15 @@
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped into undebuggable function\n");
 
+/*teawater rec begin----------------------------------------------------------*/
+	if (gdb_is_reverse || gdb_is_recording) {
+		record_resume_step = 1;
+		keep_going (ecs);
+		record_resume_step = 0;
+		return;
+	}
+/*teawater rec end------------------------------------------------------------*/
+
       /* 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
@@ -2585,15 +2662,28 @@
          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");
+
+/*teawater rec begin----------------------------------------------------------*/
+	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;
+	}
+/*teawater rec end------------------------------------------------------------*/
+
       stop_step = 1;
       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
       return;
     }
 
-  if ((stop_pc == ecs->sal.pc)
+/*teawater rec begin----------------------------------------------------------*/
+    //if ((stop_pc == ecs->sal.pc)
+    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))
+/*teawater rec end------------------------------------------------------------*/
     {
       /* 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.
@@ -2623,6 +2713,12 @@
          we will be in mid-line.  */
       if (debug_infrun)
 	 fprintf_unfiltered (gdb_stdlog, "infrun: stepped to a different function\n");
+/*teawater rec begin----------------------------------------------------------*/
+	if (gdb_is_recording) {
+		keep_going (ecs);
+		return;
+	}
+/*teawater rec end------------------------------------------------------------*/
       stop_step = 1;
       print_stop_reason (END_STEPPING_RANGE, 0);
       stop_stepping (ecs);
@@ -2669,11 +2765,13 @@
 static int
 currently_stepping (struct execution_control_state *ecs)
 {
+/*teawater rec begin----------------------------------------------------------*/
   return ((!ecs->handling_longjmp
 	   && ((step_range_end && step_resume_breakpoint == NULL)
 	       || trap_expected))
 	  || ecs->stepping_through_solib_after_catch
-	  || bpstat_should_step ());
+	  || bpstat_should_step () || record_resume_step);
+/*teawater rec end------------------------------------------------------------*/
 }
 
 /* Subroutine call with source code we should not step over.  Do step
diff -ruNa --exclude=CVS gdb-6.6/gdb/Makefile.in gdb-6.6-record/gdb/Makefile.in
--- gdb-6.6/gdb/Makefile.in	2006-11-25 03:54:14.000000000 +0800
+++ gdb-6.6-record/gdb/Makefile.in	2007-08-09 16:01:56.000000000 +0800
@@ -515,6 +515,7 @@
 # Links made at configuration time should not be specified here, since
 # SFILES is used in building the distribution archive.
 
+#teawater rec begin-------------------------------------------------------------
 SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c  \
 	ax-general.c ax-gdb.c \
 	bcache.c \
@@ -562,7 +563,9 @@
 	user-regs.c \
 	valarith.c valops.c valprint.c value.c varobj.c vec.c \
 	wrapper.c \
-	xml-support.c
+	xml-support.c \
+	record.c
+#teawater rec end---------------------------------------------------------------
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -919,6 +922,7 @@
 	$(CONFIG_SRCS)
 TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRCDIR)
 
+#teawater rec begin-------------------------------------------------------------
 COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	version.o \
 	annotate.o \
@@ -967,7 +971,9 @@
 	trad-frame.o \
 	tramp-frame.o \
 	solib.o solib-null.o \
-	prologue-value.o memory-map.o xml-support.o target-memory.o
+	prologue-value.o memory-map.o xml-support.o target-memory.o \
+	record.o
+#teawater rec end---------------------------------------------------------------
 
 TSOBS = inflow.o
 
diff -ruNa --exclude=CVS gdb-6.6/gdb/mips-tdep.c gdb-6.6-record/gdb/mips-tdep.c
--- gdb-6.6/gdb/mips-tdep.c	2006-08-09 05:32:37.000000000 +0800
+++ gdb-6.6-record/gdb/mips-tdep.c	2007-10-15 17:16:36.000000000 +0800
@@ -56,6 +56,11 @@
 #include "infcall.h"
 #include "floatformat.h"
 
+/*teawater rec begin----------------------------------------------------------*/
+#include "record.h"
+#include <stdint.h>
+/*teawater rec end------------------------------------------------------------*/
+
 static const struct objfile_data *mips_pdr_data;
 
 static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum);
@@ -4711,6 +4716,591 @@
   internal_error (__FILE__, __LINE__, _("unknown ABI string"));
 }
 
+/*teawater rec begin----------------------------------------------------------*/
+static CORE_ADDR	mips_delay_slot_addr;
+static CORE_ADDR	mips_target_addr;
+
+static int
+mips_record_32 (CORE_ADDR pc)
+{
+	uint32_t			insn = (uint32_t)mips_fetch_instruction (pc);
+	uint32_t			opcode;
+	const struct mips_regnum	*regnum = mips_regnum (current_gdbarch);
+	int				add_pc = 1;
+
+	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:
+					mips_target_addr = read_register ((insn >> 21) & 0x1f);
+					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);
+							}
+						}
+						mips_target_addr = read_register ((insn >> 21) & 0x1f);
+						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:
+					if (read_register ((insn >> 21) & 0x1f) < 0) {
+						goto set_imm_delay_slot_pc;
+					}
+					break;
+				/* bgez */
+				case 0x01:
+					if (read_register ((insn >> 21) & 0x1f) >= 0) {
+						goto set_imm_delay_slot_pc;
+					}
+					break;
+				/* bltzl */
+				case 0x02:
+					if (read_register ((insn >> 21) & 0x1f) < 0) {
+						goto set_imm_delay_slot_pc;
+					}
+					else {
+						goto set_pc;
+					}
+					break;
+				/* bgezl */
+				case 0x03:
+					if (read_register ((insn >> 21) & 0x1f) >= 0) {
+						goto set_imm_delay_slot_pc;
+					}
+					else {
+						goto set_pc;
+					}
+					break;
+				/* bltzal */
+				case 0x10:
+					if (record_arch_list_add_reg (31)) {
+						return (-1);
+					}
+					if (read_register ((insn >> 21) & 0x1f) < 0) {
+						goto set_imm_delay_slot_pc;
+					}
+					break;
+				/* bgezal */
+				case 0x11:
+					if (record_arch_list_add_reg (31)) {
+						return (-1);
+					}
+					if (read_register ((insn >> 21) & 0x1f) >= 0) {
+						goto set_imm_delay_slot_pc;
+					}
+					break;
+				/* bltzall */
+				case 0x12:
+					if (record_arch_list_add_reg (31)) {
+						return (-1);
+					}
+					if (read_register ((insn >> 21) & 0x1f) < 0) {
+						goto set_imm_delay_slot_pc;
+					}
+					else {
+						goto set_pc;
+					}
+					break;
+				/* bgezall */
+				case 0x13:
+					if (record_arch_list_add_reg (31)) {
+						return (-1);
+					}
+					if (read_register ((insn >> 21) & 0x1f) >= 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:
+			if (read_register ((insn >> 21) & 0x1f) == read_register ((insn >> 16) & 0x1f)) {
+				goto set_imm_delay_slot_pc;
+			}
+			break;
+
+		/* bne */
+		case 0x05:
+			if (read_register ((insn >> 21) & 0x1f) != read_register ((insn >> 16) & 0x1f)) {
+				goto set_imm_delay_slot_pc;
+			}
+			break;
+
+		/* blez */
+		case 0x06:
+			if (read_register ((insn >> 21) & 0x1f) <= 0) {
+				goto set_imm_delay_slot_pc;
+			}
+			break;
+
+		/* bgtz */
+		case 0x07:
+			if (read_register ((insn >> 21) & 0x1f) > 0) {
+				goto set_imm_delay_slot_pc;
+			}
+			break;
+
+		/* beql */
+		case 0x14:
+			if (read_register ((insn >> 21) & 0x1f) == read_register ((insn >> 16) & 0x1f)) {
+				goto set_imm_delay_slot_pc;
+			}
+			else {
+				goto set_pc;
+			}
+			break;
+
+		/* bnel */
+		case 0x15:
+			if (read_register ((insn >> 21) & 0x1f) != read_register ((insn >> 16) & 0x1f)) {
+				goto set_imm_delay_slot_pc;
+			}
+			else {
+				goto set_pc;
+			}
+			break;
+
+		/* blezl */
+		case 0x16:
+			if (read_register ((insn >> 21) & 0x1f) <= 0) {
+				goto set_imm_delay_slot_pc;
+			}
+			else {
+				goto set_pc;
+			}
+			break;
+
+		/* bgtzl */
+		case 0x17:
+			if (read_register ((insn >> 21) & 0x1f) > 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 */
+				addr = (insn >> 21) & 0x1f;
+				addr = read_register (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;
+}
+
+static int
+mips_record (void)
+{
+	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 (void)
+{
+	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 (current_gdbarch);
+	regcache_cooked_read_unsigned (current_regcache, regnum->pc, &pc);
+	if (gdb_is_reverse) {
+		pc -= 4;
+	}
+	else {
+		pc += 4;
+	}
+	regcache_cooked_write_unsigned (current_regcache, regnum->pc, pc);
+}
+/*teawater rec end------------------------------------------------------------*/
+
 static struct gdbarch *
 mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
@@ -5163,6 +5753,11 @@
   frame_base_append_sniffer (gdbarch, mips_insn16_frame_base_sniffer);
   frame_base_append_sniffer (gdbarch, mips_insn32_frame_base_sniffer);
 
+/*teawater rec begin----------------------------------------------------------*/
+  set_gdbarch_record (gdbarch, mips_record);
+  set_gdbarch_record_dasm (gdbarch, mips_record_dasm);
+/*teawater rec end------------------------------------------------------------*/
+
   return gdbarch;
 }
 
diff -ruNa --exclude=CVS gdb-6.6/gdb/record.c gdb-6.6-record/gdb/record.c
--- gdb-6.6/gdb/record.c	1970-01-01 08:00:00.000000000 +0800
+++ gdb-6.6-record/gdb/record.c	2007-10-16 11:46:16.000000000 +0800
@@ -0,0 +1,432 @@
+/* Record v0.1.0 for GDB, the GNU debugger.
+   Written by Teawater 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#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 "remote-utils.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 "record.h"
+
+extern struct bp_location	*bp_location_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;
+
+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);
+	}
+}
+
+void
+record_message (void)
+{
+	int	ret;
+	int	need_dasm = 0;
+
+	record_arch_list_head = NULL;
+	record_arch_list_tail = NULL;
+
+	if (gdbarch_record (current_gdbarch)) {
+		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;
+	}
+}
+
+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;
+	}
+}
+
+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 = 1;
+	rec->u.reg.num = num;
+
+	regcache_cooked_read (current_regcache, num, rec->u.reg.val);
+
+	record_arch_list_add (rec);
+
+	return (0);
+}
+
+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 = 2;
+	rec->u.mem.addr = addr;
+	rec->u.mem.len = len;
+
+	if (target_read_memory (addr, rec->u.mem.val, len)) {
+		xfree (rec->u.reg.val);
+		xfree (rec);
+		return (-1);
+	}
+
+	record_arch_list_add (rec);
+
+	return (0);
+}
+
+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 = 0;
+
+	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;
+}
+
+ptid_t
+record_wait (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;
+	
+	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 (debug_record) {
+				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 == 1) {
+			/* 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 (current_regcache, record_list->u.reg.num, reg);
+			regcache_cooked_write (current_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 == 2) {
+			/* 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 bp_location	*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 (current_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 = bp_location_chain; b; b = b->next) {
+				if (b->inserted) {
+					if (b->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 (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 ();
+	}
+	else {
+		gdb_is_recording = 1;
+		printf_unfiltered (_("record: record and reverse function is 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"));
+	}
+	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"));
+	}
+}
+
+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 or stop the record and reverse function."));
+	add_com_alias ("rec", "record", 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);
+}
diff -ruNa --exclude=CVS gdb-6.6/gdb/record.h gdb-6.6-record/gdb/record.h
--- gdb-6.6/gdb/record.h	1970-01-01 08:00:00.000000000 +0800
+++ gdb-6.6-record/gdb/record.h	2007-10-16 11:46:41.000000000 +0800
@@ -0,0 +1,65 @@
+/* Record v0.1.0 for GDB, the GNU debugger.
+   Written by Teawater 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#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;
+
+typedef struct	record_s {
+	struct	record_s	*prev;
+	struct	record_s	*next;
+	int	type;	/* 1 reg 2 mem 0 end */
+	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 void		record_message (void);
+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 (ptid_t ptid, struct target_waitstatus * status);
+extern void		record_close (void);
+#endif	//_RECORD_H_
diff -ruNa --exclude=CVS gdb-6.6/gdb/target.c gdb-6.6-record/gdb/target.c
--- gdb-6.6/gdb/target.c	2006-10-18 05:55:23.000000000 +0800
+++ gdb-6.6-record/gdb/target.c	2007-10-16 11:49:47.000000000 +0800
@@ -40,6 +40,9 @@
 #include "gdb_assert.h"
 #include "gdbcore.h"
 #include "exceptions.h"
+/*teawater rec begin----------------------------------------------------------*/
+#include "record.h"
+/*teawater rec end------------------------------------------------------------*/
 
 static void target_info (char *, int);
 
@@ -2034,6 +2037,11 @@
 void
 target_close (struct target_ops *targ, int quitting)
 {
+/*teawater rec begin----------------------------------------------------------*/
+	if (gdb_is_recording) {
+		record_close ();
+	}
+/*teawater rec end------------------------------------------------------------*/
   if (targ->to_xclose != NULL)
     targ->to_xclose (targ, quitting);
   else if (targ->to_close != NULL)
