public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
* GDB record target 0.1.0 for MIPS GDB-6.6 release (It make GDB support Reversible Debugging)
@ 2007-10-17  2:04 Tea
  0 siblings, 0 replies; only message in thread
From: Tea @ 2007-10-17  2:04 UTC (permalink / raw)
  To: gdb

[-- Attachment #1: Type: text/plain, Size: 4090 bytes --]

Hi all,

The old version of GDB record cannot show the value of the variable
because it doesn't record the memory change. GDB record target 0.1.0
disassemble the instruction that will be executed to get which memory
and register will be changed and record them to record all the program
running message.
Because need add disassemble the instruction function on the arch, the
record only support MIPS. I only test record with QEMU and Linux
Kernel because the condition is limited.
Please give me your thought about the "record". Thanks a lot.

To make and install the GDB record target 0.1.0 with GDB-6.6-mips:
tar vxjf gdb-6.6.tar.bz2
patch -p0 < gdb-6.6-record-0.1.0.patch
tar vxjf gdb-6.6.tar.bz2
patch -p0 < gdb-6.6-record-0.1.0.patch
mkdir bgdb
cd bgdb
../gdb-6.6/configure --target=mips
make
make install

The following is how to use the record:
mips-gdb ../../../qemu/linux-2.6.18.2/vmlinux
(gdb) target remote localhost:1234
#You need run QEMU with the options "-S -s" before use this command.
(gdb) b main.c:499
Breakpoint 1 at 0x8010e64c: file init/main.c, line 499.
(gdb) c
Continuing.
Breakpoint 1, start_kernel () at init/main.c:499
499             printk(KERN_NOTICE "Kernel command line: %s\n",
saved_command_line);
(gdb) record
record: record and reverse function is started.
#The abbreviation of this command is "rec".
(gdb) n
#It need wait a moment because record will spend some time.
500             parse_early_param();
(gdb) reverse
record: GDB is set to reverse debug mode.
#The abbreviation of this command is "rev".
(gdb) b vprintk
Breakpoint 2 at 0x800307b8: file kernel/printk.c, line 515.
(gdb) c
Continuing.
Breakpoint 2, vprintk (fmt=0x0, args=0x0) at kernel/printk.c:515
515             if (unlikely(oops_in_progress) && printk_cpu ==
smp_processor_id())
(gdb) reverse
record: GDB is set to normal debug mode.
#But the running message is still gotten from the record message.
(gdb) n
507     {
(gdb)
515             if (unlikely(oops_in_progress) && printk_cpu ==
smp_processor_id())
(gdb)
521             local_irq_save(flags);
(gdb)
527             printed_len = vscnprintf(printk_buf,
sizeof(printk_buf), fmt, args);
(gdb)
524             printk_cpu = smp_processor_id();
(gdb)
527             printed_len = vscnprintf(printk_buf,
sizeof(printk_buf), fmt, args);
(gdb) p printk_cpu
$1 = 4294967295
(gdb) n
524             printk_cpu = smp_processor_id();
(gdb) p printk_cpu
$2 = 4294967295
(gdb) n
527             printed_len = vscnprintf(printk_buf,
sizeof(printk_buf), fmt, args);
(gdb) p printk_cpu
$3 = 0
(gdb) p printed_len
$4 = 0
(gdb) n
warning: GDB can't find the start of the function at 0xffffffff.

    GDB is unable to find the start of the function at 0xffffffff
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
    This problem is most likely caused by an invalid program counter or
stack pointer.
    However, if you think GDB should simply search farther back
from 0xffffffff for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.
533             for (p = printk_buf; *p; p++) {
(gdb) p printed_len
$5 = 0
(gdb) n
534                     if (log_level_unknown) {
(gdb) p printed_len
$6 = 87
(gdb) rev
record: GDB is set to reverse debug mode.
(gdb) n
0xffffffff80030878      533             for (p = printk_buf; *p; p++) {
(gdb)
warning: GDB can't find the start of the function at 0xffffffff.
0xffffffff80030868      527             printed_len =
vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
(gdb) p printed_len
$7 = 0
(gdb) p printk_cpu
$8 = 0
(gdb) n
524             printk_cpu = smp_processor_id();
(gdb)
0xffffffff8003085c      527             printed_len =
vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);
(gdb) p printk_cpu
$9 = 4294967295

You can find out the change of the values of printk_cpu and
printed_len when the GDB normal debug and reverse debug.

Thanks,
teawater


Signed-Off-By: Teawater Zhu <teawater@gmail.com>

[-- Attachment #2: gdb-6.6-record-0.1.0.patch --]
[-- Type: application/octet-stream, Size: 39268 bytes --]

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)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-10-17  2:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-10-17  2:04 GDB record target 0.1.0 for MIPS GDB-6.6 release (It make GDB support Reversible Debugging) Tea

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).