This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GDB record target 0.0.2 for GDB-6.6 release (It make GDB support Reversible Debugging)


Hi All,
This patch has two parts.
The first part has some commands that can record running message such
as the program pc register value and some frame message to a record
file.
The second part has the target "record" can open this record file and
debug the program. And if the current target is the "record", you can
use command "reverse" set debug to the reverse debug mode. If you set
GDB to the reverse debug mode. The program will reverse run. Most of
GDB command such as "step", "next" and "breakpoint" can be use in this
mode.
To get more messages about the patch you can read the introduction of
GDB record target 0.0.1
(http://sourceware.org/ml/gdb/2007-08/msg00094.html).

The main change between 0.0.1 and 0.0.2 is that the user can set multi
record and each record can be stop any time. The flowing is the
commands introduction.
record (rec) filename	This command will let GDB open a file that name
is "filename" (It will be "now.rec" if not set.) and begin to record
running message to it. After call this command, all of the GDB
commands (such as step, next and continue) still can be use.
set recordnum num	User can use this command to set the number of the
next record.
delete record num	Stop and delete the record that number is "num". All
of the records will be stopped and deleted if "num" is not set.
enable record num	Start the record that number is "num". All of the
records will be started if "num" is not set.
disable record num	Stop the record that number is "num". All of the
records will be stopped if "num" is not set.
reverse			If the current target is the "record", you can use command
"reverse" set debug to the reverse debug mode. If you set GDB to the
reverse debug mode. The program will reverse run. Most of GDB command
such as "step", "next" and "breakpoint" can be use in this mode.

The new command will work well with breakpoint to record part of code.
The following is how to record the running message of function "cool".
cat 1.c
void
cool ()
{
        int     b = 1;

        b += 1;
        b += 2;

        printf ("123");

        b = 0;
}
int
main(int argc,char *argv[],char *envp[])
{
        int     a = 0;

        printf ("1\n");

        cool ();

        a = 1;
        a += 2;

        return (0);
}
gcc -g 1.c
./gdb a.out
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
Using host libthread_db library "/lib/tls/libthread_db.so.1".
Setting up the environment for debugging gdb.
Function "internal_error" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
Function "info_command" not defined.
Make breakpoint pending on future shared library load? (y or [n])
[answered N; input not from terminal]
/home/qwang/rec/bgdb/gdb/.gdbinit:8: Error in sourced command file:
No breakpoint number 0.
(gdb) b cool
Breakpoint 1 at 0x804834a: file 1.c, line 4.
(gdb) commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>silent
>set recordnum 1
>rec
>c
>end
(gdb) b 12
Breakpoint 2 at 0x8048373: file 1.c, line 12.
(gdb) commands 2
Type commands for when breakpoint 2 is hit, one per line.
End with a line saying just "end".
>silent
>d rec 1
>c
>end
(gdb) r
Starting program: /home/qwang/rec/bgdb/gdb/a.out
1
During symbol reading, incomplete CFI data; unspecified registers
(e.g., eax) at 0x8048364.
123
Program exited normally.
(gdb) target rec
Record the paogram running message to the file "now.rec".
cool () at 1.c:4
4               int     b = 1;
(gdb) n
6               b += 1;
(gdb)
7               b += 2;
(gdb) c
Continuing.
cool () at 1.c:11
11              b = 0;
(gdb) rev
GDB is set to reverse debug mode.
(gdb) d
Delete all breakpoints? (y or n) y
(gdb) n
0x08048369      9               printf ("123");
(gdb)
0x08048359      7               b += 2;
(gdb)
0x08048354      6               b += 1;
(gdb)
4               int     b = 1;
(gdb) n
cool () at 1.c:4
4               int     b = 1;
(gdb) quit

In the next version of record, I will make it can record all of the
registers and make the format of the record file more efficient than
old version.
Please give me your thought about the "record". Thanks a lot.

Thanks,
teawater

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

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

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-08-15 17:36:27.000000000 +0800
@@ -52,6 +52,14 @@
 #include "gdb_assert.h"
 #include "mi/mi-common.h"

+/*teawater rec
begin----------------------------------------------------------*/
+extern unsigned int	gdb_is_recording;
+extern int		gdb_is_reverse;
+static int		record_resume_step = 0;
+
+extern void		record_message (void);
+/*teawater rec
end------------------------------------------------------------*/
+
 /* Prototypes for local functions */

 static void signals_info (char *, int);
@@ -532,6 +540,13 @@
     fprintf_unfiltered (gdb_stdlog, "infrun: resume (step=%d, signal=%d)\n",
 			step, sig);

+/*teawater rec
begin----------------------------------------------------------*/
+	if (gdb_is_recording) {
+		step = 1;
+		record_message ();
+	}
+/*teawater rec
end------------------------------------------------------------*/
+
   /* FIXME: calling breakpoint_here_p (read_pc ()) three times! */


@@ -1916,11 +1931,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 +2447,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 +2518,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 +2568,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) {
+		if (stop_pc != ecs->sal.pc) {
+			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 +2591,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 +2649,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 +2700,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 +2752,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/list.h gdb-6.6-record/gdb/list.h
--- gdb-6.6/gdb/list.h	1970-01-01 08:00:00.000000000 +0800
+++ gdb-6.6-record/gdb/list.h	2007-08-10 12:19:41.000000000 +0800
@@ -0,0 +1,57 @@
+#ifndef _LIST_H_
+#define _LIST_H_
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+static __inline__ void __list_add(struct list_head * new,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+static __inline__ void list_add_tail(struct list_head *new, struct
list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+static __inline__ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static __inline__ void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+static __inline__ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+#endif	//_LIST_H_
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-10 12:19:41.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/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-08-15 18:06:01.000000000 +0800
@@ -0,0 +1,831 @@
+/* Record v0.0.2 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 "list.h"
+
+
+#define RECORD_DEF_FILE		"now.rec"
+
+
+/* ----------------------------------------------------------------------------------------------------------------------------------------------------------
*/
+/* target */
+#define MAGIC_NULL_PID		42000
+#define SIZE_OF_INSN		(sizeof (CORE_ADDR) * 10)
+
+int		gdb_is_reverse = 0;
+
+static struct target_ops	record_ops;
+static sigset_t			record_maskall;
+static int			record_fd = -1;
+static char			*record_mem, *record_mem_begin, *record_mem_end;
+static size_t			record_mem_size;
+static int			record_resumed = 0;
+static int			record_step;
+static int			record_get_sig = 0;
+
+static LIST_HEAD(record_breakpoint_list);
+typedef struct	record_breakpoint_s {
+	struct list_head	list;
+	CORE_ADDR		addr;
+} record_breakpoint_t;
+static uint32_t			record_software_bp = 0;
+
+
+static void			record_open (char *name, int from_tty);
+static void			record_close (int quitting);
+static void			record_stop (void);
+static void			init_record_ops (void);
+
+
+static void
+record_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
+{
+	int		level = frame_relative_level (next_frame);
+	CORE_ADDR	tmp;
+
+	if (level == -1) {
+		this_id->stack_addr = (*(CORE_ADDR *)(record_mem + sizeof (CORE_ADDR)));
+		this_id->code_addr = (*(CORE_ADDR *)(record_mem + sizeof (CORE_ADDR) * 2));
+		this_id->special_addr = (*(CORE_ADDR *)(record_mem + sizeof
(CORE_ADDR) * 3));
+		tmp = (*(CORE_ADDR *)(record_mem + sizeof (CORE_ADDR) * 4));
+		this_id->stack_addr_p = (tmp >> 0) & 0x1;
+		this_id->code_addr_p = (tmp >> 1) & 0x1;
+		this_id->special_addr_p = (tmp >> 2) & 0x1;
+	}
+	else if (level == 0) {
+		this_id->stack_addr = (*(CORE_ADDR *)(record_mem + sizeof (CORE_ADDR) * 6));
+		this_id->code_addr = (*(CORE_ADDR *)(record_mem + sizeof (CORE_ADDR) * 7));
+		this_id->special_addr = (*(CORE_ADDR *)(record_mem + sizeof
(CORE_ADDR) * 8));
+		tmp = (*(CORE_ADDR *)(record_mem + sizeof (CORE_ADDR) * 9));
+		this_id->stack_addr_p = (tmp >> 0) & 0x1;
+		this_id->code_addr_p = (tmp >> 1) & 0x1;
+		this_id->special_addr_p = (tmp >> 2) & 0x1;
+	}
+	else {
+		this_id->stack_addr_p = 0;
+		this_id->code_addr_p = 0;
+		this_id->special_addr_p = 0;
+	}
+}
+
+static void
+record_prev_register (struct frame_info *next_frame, void
**this_cache, int regnum, int *optimizedp, enum lval_type *lvalp,
CORE_ADDR *addrp, int *realnump, gdb_byte *valuep)
+{
+	int	level = frame_relative_level (next_frame);
+
+	if (level == -1 && regnum == gdbarch_pc_regnum (current_gdbarch)) {
+		memcpy (valuep, record_mem + sizeof (CORE_ADDR) * 5, sizeof (CORE_ADDR));
+	}
+}
+
+static int
+record_sniffer (const struct frame_unwind *self, struct frame_info
*next_frame, void **this_prologue_cache)
+{
+	if (current_target.to_shortname && strcmp
(current_target.to_shortname, "record") == 0) {
+		return (1);
+	}
+
+	return (0);
+}
+
+static const struct frame_unwind	record_unwind = {
+	NORMAL_FRAME,
+	record_this_id,
+	record_prev_register,
+	NULL,
+	record_sniffer
+};
+
+static void
+record_open (char *name, int from_tty)
+{
+	struct stat	statbuf;
+
+	target_preopen (from_tty);
+
+	{
+		static int	record_unwind_init = 0;
+		if (!record_unwind_init) {
+			frame_unwind_prepend_unwinder (current_gdbarch, &record_unwind);
+			record_unwind_init = 1;
+		}
+	}
+
+	/* open file */
+	if (name) {
+		printf_unfiltered (_("Record the paogram running message to the
file \"%s\".\n"), name);
+		record_fd = open (name, O_RDONLY);
+	}
+	else {
+		printf_unfiltered (_("Record the paogram running message to the
file \"%s\".\n"), RECORD_DEF_FILE);
+		record_fd = open (RECORD_DEF_FILE, O_RDONLY);
+	}
+	if (record_fd < 0) {
+		error (_("Open file error."));
+	}
+
+	/*  get & check record_mem_size */
+	if (fstat (record_fd, &statbuf) < 0) {
+		record_close (0);
+		error (_("Get size of file error."));
+	}
+	record_mem_size = statbuf.st_size;
+	if ((record_mem_size < SIZE_OF_INSN) || (record_mem_size %
SIZE_OF_INSN != 0)) {
+		record_close (0);
+		error (_("The size of file is error."));
+	}
+
+	/*  mmap record_mem */
+	record_mem = mmap (0, record_mem_size, PROT_READ, MAP_FILE |
MAP_SHARED, record_fd, 0);
+	if (record_mem == (caddr_t)-1) {
+		record_close (0);
+		error (_("Mmap file is error."));
+	}
+	record_mem_begin = record_mem;
+	record_mem_end = record_mem + record_mem_size - SIZE_OF_INSN;
+	/* BAK */
+	/*
+	record_mem = record_mem_end;
+	gdb_is_reverse = 1;
+	*/
+
+	reopen_exec_file ();
+	reread_symbols ();
+
+	push_target (&record_ops);
+
+	inferior_ptid = pid_to_ptid (MAGIC_NULL_PID);
+	remove_breakpoints ();
+	init_wait_for_inferior ();
+	/* insert_breakpoints (); */
+	clear_proceed_status ();
+	stop_stack_dummy = 1;
+
+	no_shared_libraries (NULL, 0);
+	/*start_remote (from_tty);*/
+	init_thread_list ();
+	init_wait_for_inferior ();
+	stop_soon = STOP_QUIETLY;
+	/* trap_expected = 0; */
+	wait_for_inferior ();
+	normal_stop ();
+}
+
+static void
+record_close (int quitting)
+{
+	if (record_fd >= 0) {
+		close (record_fd);
+		record_fd = -1;
+	}
+	stop_stack_dummy = 0;
+	gdb_is_reverse = 0;
+}
+
+static void
+record_kill (void)
+{
+	record_close (0);
+}
+
+static void
+record_resume (ptid_t ptid, int step, enum target_signal siggnal)
+{
+	record_resumed = 1;
+	record_step = step;
+}
+
+static void
+record_sig_handler (int signo)
+{
+	record_get_sig = 1;
+	target_stop ();
+}
+
+static ptid_t
+record_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+	if (record_resumed) {
+		struct sigaction	act, old_act;
+
+		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 {
+			if ((gdb_is_reverse && record_mem <= record_mem_begin) ||
(!gdb_is_reverse && record_mem >= record_mem_end)) {
+				stop_soon = STOP_QUIETLY;
+				break;
+			}
+			if (record_software_bp) {
+				struct list_head	*list,*n;
+				record_breakpoint_t	*rbp = NULL;
+
+				list_for_each_safe(list, n, &record_breakpoint_list) {
+					rbp = list_entry(list, record_breakpoint_t, list);
+					if (rbp->addr == (*(CORE_ADDR *)record_mem)) {
+						break;
+					}
+					rbp = NULL;
+				}
+				if (rbp) {
+					break;
+				}
+			}
+			if (gdb_is_reverse) {
+				record_mem -= SIZE_OF_INSN;
+			}
+			else {
+				record_mem += SIZE_OF_INSN;
+			}	
+		} while (!record_step);
+
+		if (sigaction (SIGALRM, &old_act, NULL)) {
+			perror_with_name (_("sigaction"));
+		}
+		record_resumed = 0;
+	}
+
+	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);
+}
+
+static void
+record_fetch_registers (int regnum)
+{
+	if (regnum >= 0) {
+		if (regnum == gdbarch_pc_regnum (current_gdbarch)) {
+			regcache_raw_supply (current_regcache, regnum, record_mem);
+		}
+		else {
+			regcache_raw_supply (current_regcache, regnum, NULL);
+		}
+	}
+	else {
+		int	i;
+
+		for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++) {
+			record_fetch_registers (i);
+		}
+	}
+}
+
+static void
+record_store_registers (int regnum)
+{
+}
+
+static int
+record_insert_breakpoint (struct bp_target_info *bp_tgt)
+{
+	record_breakpoint_t	*rbp = (record_breakpoint_t
*)xmalloc(sizeof(record_breakpoint_t));
+
+	if (!rbp) {
+		error (_("Don't has enough memory to insert breakpoint"));
+	}
+	rbp->addr = bp_tgt->placed_address;
+	list_add_tail(&rbp->list, &record_breakpoint_list);
+	record_software_bp ++;
+
+	return (0);
+}
+
+static int
+record_remove_breakpoint (struct bp_target_info *bp_tgt)
+{
+	struct list_head	*list,*n;
+	record_breakpoint_t	*rbp = NULL;
+
+	list_for_each_safe(list, n, &record_breakpoint_list) {
+		rbp = list_entry(list, record_breakpoint_t, list);
+		if (rbp->addr == bp_tgt->placed_address) {
+			break;
+		}
+		rbp = NULL;
+	}
+	if (rbp) {
+		list_del_init(&rbp->list);
+		xfree(rbp);
+		record_software_bp --;
+	}
+
+	return (0);
+}
+
+static void
+record_stop (void)
+{
+	record_step = 1;
+}
+
+static void
+init_record_ops (void)
+{
+	record_ops.to_shortname = "record";
+	record_ops.to_longname = "Debug record file";
+	record_ops.to_doc = "Debug a record file.\n"
+	                   "The argument is the directory name of a record file.";
+	record_ops.to_open = record_open;
+	record_ops.to_close = record_close;
+	record_ops.to_kill = record_kill;
+	record_ops.to_resume = record_resume;
+	record_ops.to_wait = record_wait;
+	record_ops.to_fetch_registers = record_fetch_registers;
+	record_ops.to_store_registers = record_store_registers;
+	record_ops.to_insert_breakpoint = record_insert_breakpoint;
+	record_ops.to_remove_breakpoint = record_remove_breakpoint;
+	record_ops.to_stop = record_stop;
+#if 0
+	record_ops.to_attach = record_attach;
+	record_ops.to_detach = record_detach;
+	record_ops.to_disconnect = record_disconnect;
+	record_ops.to_prepare_to_store = record_prepare_to_store;
+	record_ops.to_load = generic_load;
+	record_ops.to_create_inferior = record_create_inferior;
+	record_ops.to_mourn_inferior = record_mourn_inferior;
+	record_ops.to_stop = record_stop;
+	record_ops.to_xfer_partial = record_xfer_partial;
+	record_ops.deprecated_xfer_memory = record_xfer_memory;
+	record_ops.to_has_all_memory = 1;
+	record_ops.to_has_memory = 1;
+#endif
+	record_ops.to_stratum = process_stratum;
+	record_ops.to_has_stack = 1;
+	record_ops.to_has_registers = 1;
+	record_ops.to_has_execution = 1;
+	record_ops.to_has_thread_control = tc_none;
+	record_ops.to_magic = OPS_MAGIC;
+}
+
+static void
+set_gdb_is_reverse (char *args, int from_tty)
+{
+	if (current_target.to_shortname && strcmp
(current_target.to_shortname, "record") == 0) {
+		if (gdb_is_reverse) {
+			gdb_is_reverse = 0;
+			printf_unfiltered (_("GDB is set to normal debug mode.\n"));
+		}
+		else {
+			gdb_is_reverse = 1;
+			printf_unfiltered (_("GDB is set to reverse debug mode.\n"));
+		}
+	}
+	else {
+		error (_("reverse can only be run on record target."));
+	}
+}
+/* ----------------------------------------------------------------------------------------------------------------------------------------------------------
*/
+/* command */
+unsigned int	gdb_is_recording = 0;
+
+typedef struct	record_s {
+	struct list_head	list;
+	unsigned int		num;
+	char			*filename;
+	int			fd;
+	CORE_ADDR		pc;
+	int			enable;
+} record_t;
+static LIST_HEAD(record_list);
+static int	recordnum = 1;
+
+static record_t *	record_find (unsigned int num);
+static void		record_release (record_t *rec);
+static void		record_print (record_t *rec);
+static void		set_recordnum (char *ignore_args, int from_tty, struct
cmd_list_element *c);
+static void		record_add (char *args, int from_tty);
+extern void		record_delete (char *args, int from_tty);
+static void		record_enable (char *args, int from_tty);
+static void		record_disable (char *args, int from_tty);
+extern void		record_message (void);
+
+static record_t *
+record_find (unsigned int num)
+{
+	struct list_head	*list,*n;
+	record_t		*rtmp = NULL;
+	record_t		*rec = NULL;
+
+	list_for_each_safe(list, n, &record_list) {
+		rtmp = list_entry(list, record_t, list);
+		if (rtmp->num == num) {
+			rec = rtmp;
+			break;
+		}
+	}
+
+	return (rec);
+}
+
+static void
+record_release (record_t *rec)
+{
+	if (rec->fd >= 0) {
+		flock (rec->fd, LOCK_UN);
+		close (rec->fd);
+	}
+
+	if (rec->filename) {
+		xfree (rec->filename);
+	}
+
+	xfree (rec);
+}
+
+static void
+record_print (record_t *rec)
+{
+	struct symtab_and_line	sal;
+	struct symbol		*sym;
+
+	printf_unfiltered (_("%u\t%c\t0x%s\t"), rec->num,
(rec->enable?'y':'n'), paddr_nz (rec->pc));
+
+	sym = find_pc_sect_function (rec->pc, 0);
+	if (sym) {
+		printf_unfiltered (_("at %s "), SYMBOL_PRINT_NAME (sym));
+	}
+	else {
+		printf_unfiltered (_(" \t\t"));
+	}
+
+	sal = find_pc_line (rec->pc, 0);
+	if (sal.line != 0) {
+		printf_unfiltered (_("in %s:%d\t"), sal.symtab->filename, sal.line);
+	}
+	else {
+		printf_unfiltered (_(" \t"));
+	}
+
+	printf_unfiltered (_("%s\n"), rec->filename);
+}
+
+static void
+set_recordnum (char *ignore_args, int from_tty, struct cmd_list_element *c)
+{
+	if (recordnum >= INT_MAX) {
+		recordnum = 1;
+		error (_("The number of next record is error."));
+	}
+}
+
+static void
+record_add (char *args, int from_tty)
+{
+	record_t	*rec;
+
+	/* check exec */
+	if (!target_has_execution) {
+		error (_("record: the program is not being run."));
+	}
+
+	/* alloc rec */
+	rec = xmalloc (sizeof (record_t));
+	if (!rec) {
+		error (_("Don't has enough memory to create a new record."));
+	}
+
+	/* set rec */
+	rec->filename = NULL;
+	rec->fd = -1;
+	rec->enable = 1;
+
+	/*  num */
+	while (1) {
+		if (record_find (recordnum) == NULL) {
+			break;
+		}
+		recordnum += 1;
+		if (recordnum <= 0 || recordnum >= INT_MAX) {
+			recordnum = 1;
+		}
+	}
+	rec->num = recordnum;
+
+	/*  fd */
+	if (args) {
+		rec->fd = open (args, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	}
+	else {
+		rec->fd = open (RECORD_DEF_FILE, O_WRONLY | O_CREAT | O_TRUNC |
O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	}
+	if (rec->fd < 0) {
+		printf_unfiltered (_("Open file \"%s\" error.\n"), args);
+		record_release (rec);
+		return;
+	}
+
+	/*  lock fd */
+	if (flock (rec->fd, LOCK_EX | LOCK_NB) == -1) {
+		if (args) {
+			printf_unfiltered (_("Lock file \"%s\" error.\n"), args);
+		}
+		else {
+			printf_unfiltered (_("Lock file \"%s\" error.\n"), RECORD_DEF_FILE);
+		}
+		record_release (rec);
+		return;
+	}
+
+	/*  filename */
+	if (args) {
+		rec->filename = xstrdup (args);
+	}
+	else {
+		rec->filename = xstrdup (RECORD_DEF_FILE);
+	}
+	if (!rec->filename) {
+		printf_unfiltered (_("Don't has enough memory to create a new record."));
+		record_release (rec);
+		return;
+	}
+
+	/*  pc */
+	rec->pc = read_pc ();
+
+	/*  add to list */
+	list_add_tail(&rec->list, &record_list);
+	gdb_is_recording ++;
+
+	recordnum ++;
+	if (recordnum <= 0 || recordnum >= INT_MAX) {
+		recordnum = 1;
+	}
+}
+
+static void
+record_info (char *args, int from_tty)
+{
+	record_t	*rec = NULL;
+
+	if (list_empty (&record_list)) {
+		error (_("No records."));
+	}
+	if (args) {
+		rec = record_find (atoi (args));
+		if (!rec) {
+			error (_("No record number %s."), args);
+		}
+	}
+
+	printf_unfiltered (_("Num\tEnb\tAddress\t\tWhat\t\t\tFile\n"));
+	if (rec) {
+		record_print (rec);
+	}
+	else {
+		struct list_head	*list,*n;
+
+		list_for_each_safe(list, n, &record_list) {
+			rec = list_entry(list, record_t, list);
+			record_print (rec);
+		}
+	}
+}
+
+void
+record_delete (char *args, int from_tty)
+{
+	record_t	*rec = NULL;
+
+	if (list_empty (&record_list)) {
+		return;
+	}
+	if (args) {
+		rec = record_find (atoi (args));
+		if (!rec) {
+			if (from_tty) {
+				error (_("No record number %s."), args);
+			}
+			return;
+		}
+	}
+
+	if (rec) {
+		if (rec->enable) {
+			gdb_is_recording --;
+		}
+		list_del_init(&rec->list);
+		record_release (rec);
+	}
+	else if (!from_tty || query (_("Delete all records? "))){
+		struct list_head	*list,*n;
+
+		list_for_each_safe(list, n, &record_list) {
+			rec = list_entry(list, record_t, list);
+			list_del_init(&rec->list);
+			record_release (rec);
+		}
+		gdb_is_recording = 0;
+	}
+}
+
+static void
+record_enable (char *args, int from_tty)
+{
+	record_t	*rec = NULL;
+
+	if (list_empty (&record_list)) {
+		return;
+	}
+	if (args) {
+		rec = record_find (atoi (args));
+		if (!rec) {
+			if (from_tty) {
+				error (_("No record number %s."), args);
+			}
+			return;
+		}
+	}
+
+	if (rec) {
+		if (!rec->enable) {
+			gdb_is_recording ++;
+		}
+		rec->enable = 1;
+	}
+	else {
+		struct list_head	*list,*n;
+
+		list_for_each_safe(list, n, &record_list) {
+			rec = list_entry(list, record_t, list);
+			if (!rec->enable) {
+				gdb_is_recording ++;
+			}
+			rec->enable = 1;
+		}
+	}
+}
+
+static void
+record_disable (char *args, int from_tty)
+{
+	record_t	*rec = NULL;
+
+	if (list_empty (&record_list)) {
+		return;
+	}
+	if (args) {
+		rec = record_find (atoi (args));
+		if (!rec) {
+			if (from_tty) {
+				error (_("No record number %s."), args);
+			}
+			return;
+		}
+	}
+
+	if (rec) {
+		if (rec->enable) {
+			gdb_is_recording --;
+		}
+		rec->enable = 0;
+	}
+	else {
+		struct list_head	*list,*n;
+
+		list_for_each_safe(list, n, &record_list) {
+			rec = list_entry(list, record_t, list);
+			if (rec->enable) {
+				gdb_is_recording --;
+			}
+			rec->enable = 0;
+		}
+	}
+}
+
+void
+record_message (void)
+{
+	record_t		*rec;
+	struct list_head	*list,*n;
+	CORE_ADDR		atmp[10];
+	struct frame_id		fi;
+
+	/* get the message */
+	/* pc */
+	atmp[0] = read_pc ();
+	/* current frame */
+	fi = get_frame_id (get_current_frame ());
+	atmp[1] = fi.stack_addr;
+	atmp[2] = fi.code_addr;
+	atmp[3] = fi.special_addr;
+	atmp[4] = 0;
+	if (fi.stack_addr_p) {
+		atmp[4] |= 1;
+	}
+	if (fi.code_addr_p) {
+		atmp[4] |= 1 << 1;
+	}
+	if (fi.special_addr_p) {
+		atmp[4] |= 1 << 2;
+	}
+	/* prev pc */
+	atmp[5] = frame_pc_unwind (get_current_frame ());
+	/* prev frame */
+	fi = frame_unwind_id (get_current_frame ());
+	atmp[6] = fi.stack_addr;
+	atmp[7] = fi.code_addr;
+	atmp[8] = fi.special_addr;
+	atmp[9] = 0;
+	if (fi.stack_addr_p) {
+		atmp[9] |= 1;
+	}
+	if (fi.code_addr_p) {
+		atmp[9] |= 1 << 1;
+	}
+	if (fi.special_addr_p) {
+		atmp[9] |= 1 << 2;
+	}
+
+	list_for_each_safe(list, n, &record_list) {
+		rec = list_entry(list, record_t, list);
+		if (!rec->enable) {
+			continue;
+		}
+
+		/* write the message to rec->fd*/
+		if (write (rec->fd, atmp, sizeof (CORE_ADDR) * 10) != sizeof
(CORE_ADDR) * 10) {
+			printf_unfiltered (_("Write running message to file \"%s\"
error."), rec->filename);
+			continue;
+		}
+	}
+}
+
+/* ----------------------------------------------------------------------------------------------------------------------------------------------------------
*/
+/* initialize */
+void
+_initialize_record (void)
+{
+	/*  target */
+	/*  init record_maskall */
+	if (sigfillset (&record_maskall) == -1) {
+		perror_with_name (_("sigfillset"));
+	}
+	init_record_ops ();
+	add_target (&record_ops);
+	add_com ("reverse", class_obscure, set_gdb_is_reverse, _("Set GDB to
the reverse debug mode or the normal debug mode."));
+	add_com ("rev", class_obscure, set_gdb_is_reverse, _("Set GDB to the
reverse debug mode or the normal debug mode."));
+
+	/*  command */
+	add_setshow_integer_cmd ("recordnum", no_class, &recordnum, _("Set
the number of next record."), _("Show the number of next record."),
_("This value is the number of next record."), set_recordnum, NULL,
&setlist, &showlist);
+
+	add_com ("record", class_obscure, record_add, _("Record registers
valut to file."));
+	add_com_alias ("rec", "record", class_obscure, 1);
+	add_info ("record", record_info, _("Record registers valut to file."));
+	add_info_alias ("rec", "record", 1);
+	add_cmd ("record", class_alias, record_delete, _("Record registers
valut to file."), &deletelist);
+	add_cmd ("record", class_alias, record_enable, _("Record registers
valut to file."), &enablelist);
+	add_cmd ("record", class_alias, record_disable, _("Record registers
valut to file."), &disablelist);
+}
diff -ruNa --exclude=CVS gdb-6.6/gdb/target.h gdb-6.6-record/gdb/target.h
--- gdb-6.6/gdb/target.h	2006-10-18 05:55:23.000000000 +0800
+++ gdb-6.6-record/gdb/target.h	2007-08-15 16:32:21.000000000 +0800
@@ -779,8 +779,14 @@

 /* Kill the inferior process.   Make it go away.  */

+/*teawater rec
begin----------------------------------------------------------*/
+/*
 #define target_kill() \
      (*current_target.to_kill) ()
+*/
+extern void	record_delete (char *args, int from_tty);
+#define target_kill() do {(*current_target.to_kill) (); record_delete
(NULL, 0);} while (0)
+/*teawater rec
end------------------------------------------------------------*/

 /* Load an executable file into the target process.  This is expected
    to not only bring new code into the target process, but also to
@@ -891,8 +897,13 @@

 /* The inferior process has died.  Do what is right.  */

+/*teawater rec
begin----------------------------------------------------------*/
+#define target_mourn_inferior()	do
{(*current_target.to_mourn_inferior) (); record_delete (NULL, 0);}
while (0)
+/*
 #define	target_mourn_inferior()	\
      (*current_target.to_mourn_inferior) ()
+*/
+/*teawater rec
end------------------------------------------------------------*/

 /* Does target have enough data to do a run or attach command? */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]