From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17744 invoked by alias); 28 Apr 2009 01:51:37 -0000 Received: (qmail 16778 invoked by uid 22791); 28 Apr 2009 01:51:27 -0000 X-SWARE-Spam-Status: No, hits=-1.6 required=5.0 tests=AWL,BAYES_00,SARE_MSGID_LONG40,SPF_PASS X-Spam-Check-By: sourceware.org Received: from ti-out-0910.google.com (HELO ti-out-0910.google.com) (209.85.142.186) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 28 Apr 2009 01:51:14 +0000 Received: by ti-out-0910.google.com with SMTP id a1so15178tib.12 for ; Mon, 27 Apr 2009 18:51:10 -0700 (PDT) MIME-Version: 1.0 Received: by 10.110.17.6 with SMTP id 6mr420674tiq.28.1240883470190; Mon, 27 Apr 2009 18:51:10 -0700 (PDT) In-Reply-To: <200904272254.26971.pedro@codesourcery.com> References: <200904272254.26971.pedro@codesourcery.com> Date: Tue, 28 Apr 2009 01:51:00 -0000 Message-ID: Subject: Re: [RFA] Submit process record and replay fourth time, 3/8 From: Hui Zhu To: Pedro Alves Cc: gdb-patches@sourceware.org, Marc Khouzam , Michael Snyder , Thiago Jung Bauermann , Eli Zaretskii , paawan1982@yahoo.com, Mark Kettenis Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-04/txt/msg00749.txt.bz2 This is the changelog: 2009-04-28 Hui Zhu Process record and replay target. * Makefile.in (record.c): New file. * record.c, record.h: New file. 2008-12-28 Michael Snyder * Comments, spelling, white space clean-ups. 2008-12-26 Michael Snyder * record.h: Don't export record_not_record. * record.c (record_not_record): Rename to in_record_wait. (record_not_record_set): Rename to in_record_wait_set. (record_not_record_cleanup): Rename to in_record_wait_cleanup. (record_store_registers): Check in_record_wait flag. (record_xfer_partial): Ditto. 2008-10-07 Michael Snyder * record.h (record_exec_direction): Delete. (RECORD_IS_REPLAY): Consult infrun global direction variable. * record.c: (record_wait_cleanups): Use infrun state variable. (record_wait): Ditto. (record_get_exec_direction, record_set_exec_direction): Remove. (record_can_execute_reverse): New target method. 2008-10-06 Michael Snyder * record.c (displaced_step_fixup): Remove. (record_message_cleanups): Remove displaced step handling. (record_message): Remove displaced step handling. 2008-10-06 Michael Snyder * record.c (record_regcache_raw_write_regnum): Remove. 2008-10-05 Michael Snyder * record.c, record.h: Rename execdir to exec_direction. 2008-10-02 Michael Snyder * record.c (record_open): Call target_can_async_p() instead of relying on a global variable. * record.h (record_linux_async_permitted): Delete. 2008-09-19 Michael Snyder * record.c (trivial): Fix two commas in a comment. * record.c (record_wait): On end of record log, return TARGET_WAITKIND_NO_HISTORY and let infrun decide what to do. 2008-09-06 Michael Snyder * record.c: Comment and message string cleanup. Add some function header comments. 2008-08-01 Michael Snyder * record.c (_initialize_record): Clarify language in help strings. Fix up comment format (period must be followed by two spaces). Thanks, Hui On Tue, Apr 28, 2009 at 05:54, Pedro Alves wrote: > On Monday 27 April 2009 07:00:48, Hui Zhu wrote: >> Hi Pedro, >> >> Could you please help me review this patch? > > Thank you very much. =A0This version is approved. =A0Please don't forget > a ChangeLog entry thought; I don't think I saw one. > >> >> Thanks, >> Hui >> >> On Wed, Apr 22, 2009 at 17:05, Hui Zhu wrote: >> > I fix the error in "record_gdb_operation_disable_set" in this version. >> > >> > --- >> > =A0Makefile.in | =A0 =A05 >> > =A0record.c =A0 =A0| 1289 ++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++ >> > =A0record.h =A0 =A0| =A0 32 + >> > =A03 files changed, 1324 insertions(+), 2 deletions(-) >> > >> > --- a/Makefile.in >> > +++ b/Makefile.in >> > @@ -664,7 +664,8 @@ SFILES =3D ada-exp.y ada-lang.c ada-typepr >> > =A0 =A0 =A0 =A0valarith.c valops.c valprint.c value.c varobj.c vec.c \ >> > =A0 =A0 =A0 =A0wrapper.c \ >> > =A0 =A0 =A0 =A0xml-tdesc.c xml-support.c \ >> > - =A0 =A0 =A0 inferior.c gdb_usleep.c >> > + =A0 =A0 =A0 inferior.c gdb_usleep.c \ >> > + =A0 =A0 =A0 record.c >> > >> > =A0LINTFILES =3D $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c >> > >> > @@ -816,7 +817,7 @@ COMMON_OBS =3D $(DEPFILES) $(CONFIG_OBS) $ >> > =A0 =A0 =A0 =A0solib.o solib-null.o \ >> > =A0 =A0 =A0 =A0prologue-value.o memory-map.o xml-support.o \ >> > =A0 =A0 =A0 =A0target-descriptions.o target-memory.o xml-tdesc.o xml-b= uiltin.o \ >> > - =A0 =A0 =A0 inferior.o osdata.o gdb_usleep.o >> > + =A0 =A0 =A0 inferior.o osdata.o gdb_usleep.o record.o >> > >> > =A0TSOBS =3D inflow.o >> > >> > --- /dev/null >> > +++ b/record.c >> > @@ -0,0 +1,1289 @@ >> > +/* Process record and replay target for GDB, the GNU debugger. >> > + >> > + =A0 Copyright (C) 2008, 2009 Free Software Foundation, Inc. >> > + >> > + =A0 This file is part of GDB. >> > + >> > + =A0 This program is free software; you can redistribute it and/or mo= dify >> > + =A0 it under the terms of the GNU General Public License as publishe= d by >> > + =A0 the Free Software Foundation; either version 3 of the License, or >> > + =A0 (at your option) any later version. >> > + >> > + =A0 This program is distributed in the hope that it will be useful, >> > + =A0 but WITHOUT ANY WARRANTY; without even the implied warranty of >> > + =A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the >> > + =A0 GNU General Public License for more details. >> > + >> > + =A0 You should have received a copy of the GNU General Public License >> > + =A0 along with this program. =A0If not, see . =A0*/ >> > + >> > +#include "defs.h" >> > +#include "gdbcmd.h" >> > +#include "regcache.h" >> > +#include "gdbthread.h" >> > +#include "event-top.h" >> > +#include "exceptions.h" >> > +#include "record.h" >> > + >> > +#include >> > + >> > +#define DEFAULT_RECORD_INSN_MAX_NUM =A0 =A0200000 >> > + >> > +#define RECORD_IS_REPLAY \ >> > + =A0 =A0 (record_list->next || execution_direction =3D=3D EXEC_REVERS= E) >> > + >> > +/* These are the core struct of record function. >> > + >> > + =A0 An record_entry is a record of the value change of a register >> > + =A0 ("record_reg") or a part of memory ("record_mem"). =A0And each >> > + =A0 instruction must has a struct record_entry ("record_end") that >> > points out this >> > + =A0 is the last struct record_entry of this instruction. >> > + >> > + =A0 Each struct record_entry is linked to "record_list" by "prev" an= d "next". */ >> > + >> > +struct record_reg_entry >> > +{ >> > + =A0int num; >> > + =A0gdb_byte *val; >> > +}; >> > + >> > +struct record_mem_entry >> > +{ >> > + =A0CORE_ADDR addr; >> > + =A0int len; >> > + =A0gdb_byte *val; >> > +}; >> > + >> > +enum record_type >> > +{ >> > + =A0record_end =3D 0, >> > + =A0record_reg, >> > + =A0record_mem >> > +}; >> > + >> > +struct record_entry >> > +{ >> > + =A0struct record_entry *prev; >> > + =A0struct record_entry *next; >> > + =A0enum record_type type; >> > + =A0union >> > + =A0{ >> > + =A0 =A0/* reg */ >> > + =A0 =A0struct record_reg_entry reg; >> > + =A0 =A0/* mem */ >> > + =A0 =A0struct record_mem_entry mem; >> > + =A0} u; >> > +}; >> > + >> > +/* This is the debug switch for process record. =A0*/ >> > +int record_debug =3D 0; >> > + >> > +/* These list is for execution log. =A0*/ >> > +static struct record_entry record_first; >> > +static struct record_entry *record_list =3D &record_first; >> > +static struct record_entry *record_arch_list_head =3D NULL; >> > +static struct record_entry *record_arch_list_tail =3D NULL; >> > + >> > +/* 1 ask user. 0 auto delete the last struct record_entry. =A0*/ >> > +static int record_stop_at_limit =3D 1; >> > +static int record_insn_max_num =3D DEFAULT_RECORD_INSN_MAX_NUM; >> > +static int record_insn_num =3D 0; >> > + >> > +/* The target_ops of process record. =A0*/ >> > +static struct target_ops record_ops; >> > + >> > +/* The beneath function pointers. =A0*/ >> > +static struct target_ops *record_beneath_to_resume_ops; >> > +static void (*record_beneath_to_resume) (struct target_ops *, ptid_t,= int, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 enum target_signal); >> > +static struct target_ops *record_beneath_to_wait_ops; >> > +static ptid_t (*record_beneath_to_wait) (struct target_ops *, ptid_t, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0struct target_waitstatus *); >> > +static struct target_ops *record_beneath_to_store_registers_ops; >> > +static void (*record_beneath_to_store_registers) (struct target_ops *, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct regcache *, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 int regno); >> > +static struct target_ops *record_beneath_to_xfer_partial_ops; >> > +static LONGEST (*record_beneath_to_xfer_partial) (struct target_ops *= ops, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 enum target_object object, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 const char *annex, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdb_byte *readbuf, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 const gdb_byte *writebuf, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 ULONGEST offset, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 LONGEST len); >> > +static int (*record_beneath_to_insert_breakpoint) (struct bp_target_i= nfo *); >> > +static int (*record_beneath_to_remove_breakpoint) (struct bp_target_i= nfo *); >> > + >> > +static void >> > +record_list_release (struct record_entry *rec) >> > +{ >> > + =A0struct record_entry *tmp; >> > + >> > + =A0if (!rec) >> > + =A0 =A0return; >> > + >> > + =A0while (rec->next) >> > + =A0 =A0{ >> > + =A0 =A0 =A0rec =3D rec->next; >> > + =A0 =A0} >> > + >> > + =A0while (rec->prev) >> > + =A0 =A0{ >> > + =A0 =A0 =A0tmp =3D rec; >> > + =A0 =A0 =A0rec =3D rec->prev; >> > + =A0 =A0 =A0if (tmp->type =3D=3D record_reg) >> > + =A0 =A0 =A0 xfree (tmp->u.reg.val); >> > + =A0 =A0 =A0else if (tmp->type =3D=3D record_mem) >> > + =A0 =A0 =A0 xfree (tmp->u.mem.val); >> > + =A0 =A0 =A0xfree (tmp); >> > + =A0 =A0} >> > + >> > + =A0if (rec !=3D &record_first) >> > + =A0 =A0xfree (rec); >> > +} >> > + >> > +static void >> > +record_list_release_next (void) >> > +{ >> > + =A0struct record_entry *rec =3D record_list; >> > + =A0struct record_entry *tmp =3D rec->next; >> > + =A0rec->next =3D NULL; >> > + =A0while (tmp) >> > + =A0 =A0{ >> > + =A0 =A0 =A0rec =3D tmp->next; >> > + =A0 =A0 =A0if (tmp->type =3D=3D record_reg) >> > + =A0 =A0 =A0 record_insn_num--; >> > + =A0 =A0 =A0else if (tmp->type =3D=3D record_reg) >> > + =A0 =A0 =A0 xfree (tmp->u.reg.val); >> > + =A0 =A0 =A0else if (tmp->type =3D=3D record_mem) >> > + =A0 =A0 =A0 xfree (tmp->u.mem.val); >> > + =A0 =A0 =A0xfree (tmp); >> > + =A0 =A0 =A0tmp =3D rec; >> > + =A0 =A0} >> > +} >> > + >> > +static void >> > +record_list_release_first (void) >> > +{ >> > + =A0struct record_entry *tmp =3D NULL; >> > + =A0enum record_type type; >> > + >> > + =A0if (!record_first.next) >> > + =A0 =A0return; >> > + >> > + =A0while (1) >> > + =A0 =A0{ >> > + =A0 =A0 =A0type =3D record_first.next->type; >> > + >> > + =A0 =A0 =A0if (type =3D=3D record_reg) >> > + =A0 =A0 =A0 xfree (record_first.next->u.reg.val); >> > + =A0 =A0 =A0else if (type =3D=3D record_mem) >> > + =A0 =A0 =A0 xfree (record_first.next->u.mem.val); >> > + =A0 =A0 =A0tmp =3D record_first.next; >> > + =A0 =A0 =A0record_first.next =3D tmp->next; >> > + =A0 =A0 =A0xfree (tmp); >> > + >> > + =A0 =A0 =A0if (!record_first.next) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 gdb_assert (record_insn_num =3D=3D 1); >> > + =A0 =A0 =A0 =A0 break; >> > + =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0record_first.next->prev =3D &record_first; >> > + >> > + =A0 =A0 =A0if (type =3D=3D record_end) >> > + =A0 =A0 =A0 break; >> > + =A0 =A0} >> > + >> > + =A0record_insn_num--; >> > +} >> > + >> > +/* Add a struct record_entry to record_arch_list. =A0*/ >> > + >> > +static void >> > +record_arch_list_add (struct record_entry *rec) >> > +{ >> > + =A0if (record_debug > 1) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Process record: record_= arch_list_add %s.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 host_address_to_string (= rec)); >> > + >> > + =A0if (record_arch_list_tail) >> > + =A0 =A0{ >> > + =A0 =A0 =A0record_arch_list_tail->next =3D rec; >> > + =A0 =A0 =A0rec->prev =3D record_arch_list_tail; >> > + =A0 =A0 =A0record_arch_list_tail =3D rec; >> > + =A0 =A0} >> > + =A0else >> > + =A0 =A0{ >> > + =A0 =A0 =A0record_arch_list_head =3D rec; >> > + =A0 =A0 =A0record_arch_list_tail =3D rec; >> > + =A0 =A0} >> > +} >> > + >> > +/* Record the value of a register NUM to record_arch_list. =A0*/ >> > + >> > +int >> > +record_arch_list_add_reg (struct regcache *regcache, int num) >> > +{ >> > + =A0struct record_entry *rec; >> > + >> > + =A0if (record_debug > 1) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Process record: add reg= ister num =3D %d to " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record list.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 num); >> > + >> > + =A0rec =3D (struct record_entry *) xmalloc (sizeof (struct record_en= try)); >> > + =A0rec->u.reg.val =3D (gdb_byte *) xmalloc (MAX_REGISTER_SIZE); >> > + =A0rec->prev =3D NULL; >> > + =A0rec->next =3D NULL; >> > + =A0rec->type =3D record_reg; >> > + =A0rec->u.reg.num =3D num; >> > + >> > + =A0regcache_raw_read (regcache, num, rec->u.reg.val); >> > + >> > + =A0record_arch_list_add (rec); >> > + >> > + =A0return 0; >> > +} >> > + >> > +/* Record the value of a region of memory whose address is ADDR and >> > + =A0 length is LEN to record_arch_list. =A0*/ >> > + >> > +int >> > +record_arch_list_add_mem (CORE_ADDR addr, int len) >> > +{ >> > + =A0struct record_entry *rec; >> > + >> > + =A0if (record_debug > 1) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Process record: add mem= addr =3D 0x%s len =3D %d to " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record list.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddr_nz (addr), len); >> > + >> > + =A0if (!addr) >> > + =A0 =A0return 0; >> > + >> > + =A0rec =3D (struct record_entry *) xmalloc (sizeof (struct record_en= try)); >> > + =A0rec->u.mem.val =3D (gdb_byte *) xmalloc (len); >> > + =A0rec->prev =3D NULL; >> > + =A0rec->next =3D NULL; >> > + =A0rec->type =3D record_mem; >> > + =A0rec->u.mem.addr =3D addr; >> > + =A0rec->u.mem.len =3D len; >> > + >> > + =A0if (target_read_memory (addr, rec->u.mem.val, len)) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (record_debug) >> > + =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Process record:= error reading memory at " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr =3D 0x%s l= en =3D %d.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddr_nz (addr),= len); >> > + =A0 =A0 =A0xfree (rec->u.mem.val); >> > + =A0 =A0 =A0xfree (rec); >> > + =A0 =A0 =A0return -1; >> > + =A0 =A0} >> > + >> > + =A0record_arch_list_add (rec); >> > + >> > + =A0return 0; >> > +} >> > + >> > +/* Add a record_end type struct record_entry to record_arch_list. =A0= */ >> > + >> > +int >> > +record_arch_list_add_end (void) >> > +{ >> > + =A0struct record_entry *rec; >> > + >> > + =A0if (record_debug > 1) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Process record: add end= to arch list.\n"); >> > + >> > + =A0rec =3D (struct record_entry *) xmalloc (sizeof (struct record_en= try)); >> > + =A0rec->prev =3D NULL; >> > + =A0rec->next =3D NULL; >> > + =A0rec->type =3D record_end; >> > + >> > + =A0record_arch_list_add (rec); >> > + >> > + =A0return 0; >> > +} >> > + >> > +static void >> > +record_check_insn_num (int set_terminal) >> > +{ >> > + =A0if (record_insn_max_num) >> > + =A0 =A0{ >> > + =A0 =A0 =A0gdb_assert (record_insn_num <=3D record_insn_max_num); >> > + =A0 =A0 =A0if (record_insn_num =3D=3D record_insn_max_num) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 /* Ask user what to do. =A0*/ >> > + =A0 =A0 =A0 =A0 if (record_stop_at_limit) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 int q; >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (set_terminal) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 target_terminal_ours (); >> > + =A0 =A0 =A0 =A0 =A0 =A0 q =3D yquery (_("Do you want to auto delete = previous execution " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "log entries whe= n record/replay buffer becomes " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "full (record st= op-at-limit)?")); >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (set_terminal) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 target_terminal_inferior (); >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (q) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_stop_at_limit =3D 0; >> > + =A0 =A0 =A0 =A0 =A0 =A0 else >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: inferior progr= am stopped.")); >> > + =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 } >> > + =A0 =A0} >> > +} >> > + >> > +/* Before inferior step (when GDB record the running message, inferior >> > + =A0 only can step), GDB will call this function to record the values= to >> > + =A0 record_list. =A0This function will call gdbarch_process_record to >> > + =A0 record the running message of inferior and set them to >> > + =A0 record_arch_list, and add it to record_list. =A0*/ >> > + >> > +static void >> > +record_message_cleanups (void *ignore) >> > +{ >> > + =A0record_list_release (record_arch_list_tail); >> > +} >> > + >> > +static int >> > +record_message (void *args) >> > +{ >> > + =A0int ret; >> > + =A0struct regcache *regcache =3D args; >> > + =A0struct cleanup *old_cleanups =3D make_cleanup (record_message_cle= anups, 0); >> > + >> > + =A0record_arch_list_head =3D NULL; >> > + =A0record_arch_list_tail =3D NULL; >> > + >> > + =A0/* Check record_insn_num. =A0*/ >> > + =A0record_check_insn_num (1); >> > + >> > + =A0ret =3D gdbarch_process_record (get_regcache_arch (regcache), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache= _read_pc (regcache)); >> > + =A0if (ret > 0) >> > + =A0 =A0error (_("Process record: inferior program stopped.")); >> > + =A0if (ret < 0) >> > + =A0 =A0error (_("Process record: failed to record execution log.")); >> > + >> > + =A0discard_cleanups (old_cleanups); >> > + >> > + =A0record_list->next =3D record_arch_list_head; >> > + =A0record_arch_list_head->prev =3D record_list; >> > + =A0record_list =3D record_arch_list_tail; >> > + >> > + =A0if (record_insn_num =3D=3D record_insn_max_num && record_insn_max= _num) >> > + =A0 =A0record_list_release_first (); >> > + =A0else >> > + =A0 =A0record_insn_num++; >> > + >> > + =A0return 1; >> > +} >> > + >> > +static int >> > +do_record_message (struct regcache *regcache) >> > +{ >> > + =A0return catch_errors (record_message, regcache, NULL, RETURN_MASK_= ALL); >> > +} >> > + >> > +/* Set to 1 if record_store_registers and record_xfer_partial >> > + =A0 doesn't need record. =A0*/ >> > + >> > +static int record_gdb_operation_disable =3D 0; >> > + >> > +struct cleanup * >> > +record_gdb_operation_disable_set (void) >> > +{ >> > + =A0struct cleanup *old_cleanups =3D NULL; >> > + >> > + =A0old_cleanups =3D >> > + =A0 =A0make_cleanup_restore_integer (&record_gdb_operation_disable); >> > + =A0record_gdb_operation_disable =3D 1; >> > + >> > + =A0return old_cleanups; >> > +} >> > + >> > +static void >> > +record_open (char *name, int from_tty) >> > +{ >> > + =A0struct target_ops *t; >> > + >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: record_open\= n"); >> > + >> > + =A0/* check exec */ >> > + =A0if (!target_has_execution) >> > + =A0 =A0error (_("Process record: the program is not being run.")); >> > + =A0if (non_stop) >> > + =A0 =A0error (_("Process record target can't debug inferior in non-s= top mode " >> > + =A0 =A0 =A0 =A0 =A0 =A0"(non-stop).")); >> > + =A0if (target_async_permitted) >> > + =A0 =A0error (_("Process record target can't debug inferior in async= hronous " >> > + =A0 =A0 =A0 =A0 =A0 =A0"mode (target-async).")); >> > + >> > + =A0if (!gdbarch_process_record_p (current_gdbarch)) >> > + =A0 =A0error (_("Process record: the current architecture doesn't su= pport " >> > + =A0 =A0 =A0 =A0 =A0 =A0"record function.")); >> > + >> > + =A0/* Check if record target is already running. =A0*/ >> > + =A0if (current_target.to_stratum =3D=3D record_stratum) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (!nquery >> > + =A0 =A0 =A0 =A0 (_("Process record target already running, do you wa= nt to delete " >> > + =A0 =A0 =A0 =A0 =A0 =A0"the old record log?"))) >> > + =A0 =A0 =A0 return; >> > + =A0 =A0} >> > + >> > + =A0/*Reset the beneath function pointers. =A0*/ >> > + =A0record_beneath_to_resume =3D NULL; >> > + =A0record_beneath_to_wait =3D NULL; >> > + =A0record_beneath_to_store_registers =3D NULL; >> > + =A0record_beneath_to_xfer_partial =3D NULL; >> > + =A0record_beneath_to_insert_breakpoint =3D NULL; >> > + =A0record_beneath_to_remove_breakpoint =3D NULL; >> > + >> > + =A0/* Set the beneath function pointers. =A0*/ >> > + =A0for (t =3D current_target.beneath; t !=3D NULL; t =3D t->beneath) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (!record_beneath_to_resume) >> > + =A0 =A0 =A0 =A0{ >> > + =A0 =A0 =A0 =A0 record_beneath_to_resume =3D t->to_resume; >> > + =A0 =A0 =A0 =A0 record_beneath_to_resume_ops =3D t; >> > + =A0 =A0 =A0 =A0} >> > + =A0 =A0 =A0if (!record_beneath_to_wait) >> > + =A0 =A0 =A0 =A0{ >> > + =A0 =A0 =A0 =A0 record_beneath_to_wait =3D t->to_wait; >> > + =A0 =A0 =A0 =A0 record_beneath_to_wait_ops =3D t; >> > + =A0 =A0 =A0 =A0} >> > + =A0 =A0 =A0if (!record_beneath_to_store_registers) >> > + =A0 =A0 =A0 =A0{ >> > + =A0 =A0 =A0 =A0 record_beneath_to_store_registers =3D t->to_store_re= gisters; >> > + =A0 =A0 =A0 =A0 record_beneath_to_store_registers_ops =3D t; >> > + =A0 =A0 =A0 =A0} >> > + =A0 =A0 =A0if (!record_beneath_to_xfer_partial) >> > + =A0 =A0 =A0 =A0{ >> > + =A0 =A0 =A0 =A0 record_beneath_to_xfer_partial =3D t->to_xfer_partia= l; >> > + =A0 =A0 =A0 =A0 record_beneath_to_xfer_partial_ops =3D t; >> > + =A0 =A0 =A0 =A0} >> > + =A0 =A0 =A0if (!record_beneath_to_insert_breakpoint) >> > + =A0 =A0 =A0 record_beneath_to_insert_breakpoint =3D t->to_insert_bre= akpoint; >> > + =A0 =A0 =A0if (!record_beneath_to_remove_breakpoint) >> > + =A0 =A0 =A0 record_beneath_to_remove_breakpoint =3D t->to_remove_bre= akpoint; >> > + =A0 =A0} >> > + =A0if (!record_beneath_to_resume) >> > + =A0 =A0error (_("Process record can't get to_resume.")); >> > + =A0if (!record_beneath_to_wait) >> > + =A0 =A0error (_("Process record can't get to_wait.")); >> > + =A0if (!record_beneath_to_store_registers) >> > + =A0 =A0error (_("Process record can't get to_store_registers.")); >> > + =A0if (!record_beneath_to_xfer_partial) >> > + =A0 =A0error (_("Process record can't get to_xfer_partial.")); >> > + =A0if (!record_beneath_to_insert_breakpoint) >> > + =A0 =A0error (_("Process record can't get to_insert_breakpoint.")); >> > + =A0if (!record_beneath_to_remove_breakpoint) >> > + =A0 =A0error (_("Process record can't get to_remove_breakpoint.")); >> > + >> > + =A0push_target (&record_ops); >> > + >> > + =A0/* Reset */ >> > + =A0record_insn_num =3D 0; >> > + =A0record_list =3D &record_first; >> > + =A0record_list->next =3D NULL; >> > +} >> > + >> > +static void >> > +record_close (int quitting) >> > +{ >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: record_close= \n"); >> > + >> > + =A0record_list_release (record_list); >> > +} >> > + >> > +static int record_resume_step =3D 0; >> > +static enum target_signal record_resume_siggnal; >> > +static int record_resume_error; >> > + >> > +static void >> > +record_resume (struct target_ops *ops, ptid_t ptid, int step, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 enum target_signal siggnal) >> > +{ >> > + =A0record_resume_step =3D step; >> > + =A0record_resume_siggnal =3D siggnal; >> > + >> > + =A0if (!RECORD_IS_REPLAY) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (do_record_message (get_current_regcache ())) >> > + =A0 =A0 =A0 =A0{ >> > + =A0 =A0 =A0 =A0 =A0record_resume_error =3D 0; >> > + =A0 =A0 =A0 =A0} >> > + =A0 =A0 =A0else >> > + =A0 =A0 =A0 =A0{ >> > + =A0 =A0 =A0 =A0 =A0record_resume_error =3D 1; >> > + =A0 =A0 =A0 =A0 =A0return; >> > + =A0 =A0 =A0 =A0} >> > + =A0 =A0 =A0record_beneath_to_resume (record_beneath_to_resume_ops, p= tid, 1, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0siggn= al); >> > + =A0 =A0} >> > +} >> > + >> > +static int record_get_sig =3D 0; >> > + >> > +static void >> > +record_sig_handler (int signo) >> > +{ >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: get a signal= \n"); >> > + >> > + =A0/* It will break the running inferior in replay mode. =A0*/ >> > + =A0record_resume_step =3D 1; >> > + >> > + =A0/* It will let record_wait set inferior status to get the signal >> > + =A0 =A0 SIGINT. =A0*/ >> > + =A0record_get_sig =3D 1; >> > +} >> > + >> > +static void >> > +record_wait_cleanups (void *ignore) >> > +{ >> > + =A0if (execution_direction =3D=3D EXEC_REVERSE) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (record_list->next) >> > + =A0 =A0 =A0 record_list =3D record_list->next; >> > + =A0 =A0} >> > + =A0else >> > + =A0 =A0record_list =3D record_list->prev; >> > +} >> > + >> > +/* In replay mode, this function examines the recorded log and >> > + =A0 determines where to stop. =A0*/ >> > + >> > +static ptid_t >> > +record_wait (struct target_ops *ops, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0ptid_t ptid, struct target_waitstatus *st= atus) >> > +{ >> > + =A0struct cleanup *set_cleanups =3D record_gdb_operation_disable_set= (); >> > + >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Process record: record_= wait " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record_resume_step =3D = %d\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_resume_step); >> > + >> > + =A0if (!RECORD_IS_REPLAY) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (record_resume_error) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 /* If record_resume get error, return directly. =A0*/ >> > + =A0 =A0 =A0 =A0 status->kind =3D TARGET_WAITKIND_STOPPED; >> > + =A0 =A0 =A0 =A0 status->value.sig =3D TARGET_SIGNAL_TRAP; >> > + =A0 =A0 =A0 =A0 return inferior_ptid; >> > + =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0if (record_resume_step) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 /* This is a single step. =A0*/ >> > + =A0 =A0 =A0 =A0 return record_beneath_to_wait (record_beneath_to_wai= t_ops, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ptid, status); >> > + =A0 =A0 =A0 } >> > + =A0 =A0 =A0else >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 /* This is not a single step. =A0*/ >> > + =A0 =A0 =A0 =A0 ptid_t ret; >> > + =A0 =A0 =A0 =A0 CORE_ADDR tmp_pc; >> > + >> > + =A0 =A0 =A0 =A0 while (1) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 ret =3D record_beneath_to_wait (record_benea= th_to_wait_ops, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 ptid, status); >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (status->kind =3D=3D TARGET_WAITKIND_STOP= PED >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && status->value.sig =3D=3D TARGET_S= IGNAL_TRAP) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Check if there is a breakpoint. = =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 registers_changed (); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 tmp_pc =3D read_pc (); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (breakpoint_inserted_here_p (tmp_= pc)) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* There is a breakpoint. = =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 CORE_ADDR decr_pc_after_brea= k =3D >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdbarch_decr_pc_after_br= eak >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (get_regcache_arch (get_= current_regcache ())); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (decr_pc_after_break) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache_write_pc (g= et_thread_regcache (ret), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0tmp_pc + decr_pc_after_break); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* There is not a breakpoint= . =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!do_record_message (get_= current_regcache ())) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_beneath_to_resume (re= cord_beneath_to_resume_ops, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 ptid, 1, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 record_resume_siggnal); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 /* The inferior is broken by a breakpoint or= a signal. =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 break; >> > + =A0 =A0 =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0 =A0 return ret; >> > + =A0 =A0 =A0 } >> > + =A0 =A0} >> > + =A0else >> > + =A0 =A0{ >> > + =A0 =A0 =A0struct regcache *regcache =3D get_current_regcache (); >> > + =A0 =A0 =A0int continue_flag =3D 1; >> > + =A0 =A0 =A0int first_record_end =3D 1; >> > + =A0 =A0 =A0struct cleanup *old_cleanups =3D make_cleanup (record_wai= t_cleanups, 0); >> > + =A0 =A0 =A0CORE_ADDR tmp_pc; >> > + >> > + =A0 =A0 =A0status->kind =3D TARGET_WAITKIND_STOPPED; >> > + >> > + =A0 =A0 =A0/* Check breakpoint when forward execute. =A0*/ >> > + =A0 =A0 =A0if (execution_direction =3D=3D EXEC_FORWARD) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 tmp_pc =3D regcache_read_pc (regcache); >> > + =A0 =A0 =A0 =A0 if (breakpoint_inserted_here_p (tmp_pc)) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "Process record: break at 0x%s.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = paddr_nz (tmp_pc)); >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (gdbarch_decr_pc_after_break (get_regcach= e_arch (regcache)) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && !record_resume_step) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache_write_pc (regcache, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0t= mp_pc + >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0g= dbarch_decr_pc_after_break >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(= get_regcache_arch (regcache))); >> > + =A0 =A0 =A0 =A0 =A0 =A0 goto replay_out; >> > + =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0record_get_sig =3D 0; >> > + =A0 =A0 =A0signal (SIGINT, record_sig_handler); >> > + =A0 =A0 =A0/* If GDB is in terminal_inferior mode, it will not get t= he signal. >> > + =A0 =A0 =A0 =A0 And in GDB replay mode, GDB doesn't need to be in te= rminal_inferior >> > + =A0 =A0 =A0 =A0 mode, because inferior will not executed. >> > + =A0 =A0 =A0 =A0 Then set it to terminal_ours to make GDB get the sig= nal. =A0*/ >> > + =A0 =A0 =A0target_terminal_ours (); >> > + >> > + =A0 =A0 =A0/* In EXEC_FORWARD mode, record_list points to the tail o= f prev >> > + =A0 =A0 =A0 =A0 instruction. =A0*/ >> > + =A0 =A0 =A0if (execution_direction =3D=3D EXEC_FORWARD && record_lis= t->next) >> > + =A0 =A0 =A0 record_list =3D record_list->next; >> > + >> > + =A0 =A0 =A0/* Loop over the record_list, looking for the next place = to >> > + =A0 =A0 =A0 =A0stop. =A0*/ >> > + =A0 =A0 =A0do >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 /* Check for beginning and end of log. =A0*/ >> > + =A0 =A0 =A0 =A0 if (execution_direction =3D=3D EXEC_REVERSE >> > + =A0 =A0 =A0 =A0 =A0 =A0 && record_list =3D=3D &record_first) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 /* Hit beginning of record log in reverse. = =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 status->kind =3D TARGET_WAITKIND_NO_HISTORY; >> > + =A0 =A0 =A0 =A0 =A0 =A0 break; >> > + =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 if (execution_direction !=3D EXEC_REVERSE && !record= _list->next) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 /* Hit end of record log going forward. =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 status->kind =3D TARGET_WAITKIND_NO_HISTORY; >> > + =A0 =A0 =A0 =A0 =A0 =A0 break; >> > + =A0 =A0 =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0 =A0 /* Set ptid, register and memory according to record= _list. =A0*/ >> > + =A0 =A0 =A0 =A0 if (record_list->type =3D=3D record_reg) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 /* reg */ >> > + =A0 =A0 =A0 =A0 =A0 =A0 gdb_byte reg[MAX_REGISTER_SIZE]; >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug > 1) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "Process record: record_reg %s to " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "inferior num =3D %d.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = host_address_to_string (record_list), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = record_list->u.reg.num); >> > + =A0 =A0 =A0 =A0 =A0 =A0 regcache_cooked_read (regcache, record_list-= >u.reg.num, reg); >> > + =A0 =A0 =A0 =A0 =A0 =A0 regcache_cooked_write (regcache, record_list= ->u.reg.num, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0record_list->u.reg.val); >> > + =A0 =A0 =A0 =A0 =A0 =A0 memcpy (record_list->u.reg.val, reg, MAX_REG= ISTER_SIZE); >> > + =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 else if (record_list->type =3D=3D record_mem) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 /* mem */ >> > + =A0 =A0 =A0 =A0 =A0 =A0 gdb_byte *mem =3D alloca (record_list->u.mem= .len); >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug > 1) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "Process record: record_mem %s to " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "inferior addr =3D 0x%s len =3D %d.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = host_address_to_string (record_list), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = paddr_nz (record_list->u.mem.addr), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = record_list->u.mem.len); >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (target_read_memory >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (record_list->u.mem.addr, mem, recor= d_list->u.mem.len)) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: error reading = memory at " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"addr =3D 0x%s len = =3D %d."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddr_nz (record_list->u.= mem.addr), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.len); >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (target_write_memory >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (record_list->u.mem.addr, record_lis= t->u.mem.val, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.len)) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0("Process record: error w= riting memory at " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr =3D 0x%s len =3D %= d."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddr_nz (record_list->u.= mem.addr), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.len); >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 memcpy (record_list->u.mem.val, mem, record_= list->u.mem.len); >> > + =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 else >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug > 1) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "Process record: record_end %s to " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "inferior.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = host_address_to_string (record_list)); >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (first_record_end && execution_direction = =3D=3D EXEC_REVERSE) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* When reverse excute, the first re= cord_end is the part of >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0current instruction. =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 first_record_end =3D 0; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 else >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* In EXEC_REVERSE mode, this is the= record_end of prev >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0instruction. >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0In EXEC_FORWARD mode, this is= the record_end of current >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0instruction. =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* step */ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (record_resume_step) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug > 1) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_= stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 "Process record: step.\n"); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue_flag =3D 0; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* check breakpoint */ >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 tmp_pc =3D regcache_read_pc (regcach= e); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (breakpoint_inserted_here_p (tmp_= pc)) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_= stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 "Process record: break " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 "at 0x%s.\n", >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 paddr_nz (tmp_pc)); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (gdbarch_decr_pc_after_br= eak (get_regcache_arch (regcache)) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && execution_directi= on =3D=3D EXEC_FORWARD >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && !record_resume_st= ep) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache_write_pc (regca= che, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0tmp_pc + >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0gdbarch_decr_pc_after_break >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0(get_regcache_arch (regcache))); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue_flag =3D 0; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0 =A0 if (continue_flag) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (execution_direction =3D=3D EXEC_REVERSE) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (record_list->prev) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_list =3D record_list->pre= v; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 else >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (record_list->next) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_list =3D record_list->nex= t; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 } >> > + =A0 =A0 =A0while (continue_flag); >> > + >> > + =A0 =A0 =A0signal (SIGINT, handle_sigint); >> > + >> > +replay_out: >> > + =A0 =A0 =A0if (record_get_sig) >> > + =A0 =A0 =A0 status->value.sig =3D TARGET_SIGNAL_INT; >> > + =A0 =A0 =A0else >> > + =A0 =A0 =A0 status->value.sig =3D TARGET_SIGNAL_TRAP; >> > + >> > + =A0 =A0 =A0discard_cleanups (old_cleanups); >> > + =A0 =A0} >> > + >> > + =A0do_cleanups (set_cleanups); >> > + =A0return inferior_ptid; >> > +} >> > + >> > +static void >> > +record_disconnect (struct target_ops *target, char *args, int from_tt= y) >> > +{ >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: record_disco= nnect\n"); >> > + >> > + =A0unpush_target (&record_ops); >> > + =A0target_disconnect (args, from_tty); >> > +} >> > + >> > +static void >> > +record_detach (struct target_ops *ops, char *args, int from_tty) >> > +{ >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: record_detac= h\n"); >> > + >> > + =A0unpush_target (&record_ops); >> > + =A0target_detach (args, from_tty); >> > +} >> > + >> > +static void >> > +record_mourn_inferior (struct target_ops *ops) >> > +{ >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "record_mourn_inferior\n"); >> > + >> > + =A0unpush_target (&record_ops); >> > + =A0target_mourn_inferior (); >> > +} >> > + >> > +/* Close process record target before killing the inferior process. = =A0*/ >> > + >> > +static void >> > +record_kill (struct target_ops *ops) >> > +{ >> > + =A0if (record_debug) >> > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\= n"); >> > + >> > + =A0unpush_target (&record_ops); >> > + =A0target_kill (); >> > +} >> > + >> > +/* Record registers change (by user or by GDB) to list as an instruct= ion. =A0*/ >> > + >> > +static void >> > +record_registers_change (struct regcache *regcache, int regnum) >> > +{ >> > + =A0/* Check record_insn_num. =A0*/ >> > + =A0record_check_insn_num (0); >> > + >> > + =A0record_arch_list_head =3D NULL; >> > + =A0record_arch_list_tail =3D NULL; >> > + >> > + =A0if (regnum < 0) >> > + =A0 =A0{ >> > + =A0 =A0 =A0int i; >> > + =A0 =A0 =A0for (i =3D 0; i < gdbarch_num_regs (get_regcache_arch (re= gcache)); i++) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 if (record_arch_list_add_reg (regcache, i)) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 record_list_release (record_arch_list_tail); >> > + =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: failed to record e= xecution log.")); >> > + =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 } >> > + =A0 =A0} >> > + =A0else >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (record_arch_list_add_reg (regcache, regnum)) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 record_list_release (record_arch_list_tail); >> > + =A0 =A0 =A0 =A0 error (_("Process record: failed to record execution= log.")); >> > + =A0 =A0 =A0 } >> > + =A0 =A0} >> > + =A0if (record_arch_list_add_end ()) >> > + =A0 =A0{ >> > + =A0 =A0 =A0record_list_release (record_arch_list_tail); >> > + =A0 =A0 =A0error (_("Process record: failed to record execution log.= ")); >> > + =A0 =A0} >> > + =A0record_list->next =3D record_arch_list_head; >> > + =A0record_arch_list_head->prev =3D record_list; >> > + =A0record_list =3D record_arch_list_tail; >> > + >> > + =A0if (record_insn_num =3D=3D record_insn_max_num && record_insn_max= _num) >> > + =A0 =A0record_list_release_first (); >> > + =A0else >> > + =A0 =A0record_insn_num++; >> > +} >> > + >> > +static void >> > +record_store_registers (struct target_ops *ops, struct regcache *regc= ache, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int regno) >> > +{ >> > + =A0if (!record_gdb_operation_disable) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (RECORD_IS_REPLAY) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 int n; >> > + =A0 =A0 =A0 =A0 struct cleanup *old_cleanups; >> > + >> > + =A0 =A0 =A0 =A0 /* Let user choose if he wants to write register or = not. =A0*/ >> > + =A0 =A0 =A0 =A0 if (regno < 0) >> > + =A0 =A0 =A0 =A0 =A0 n =3D >> > + =A0 =A0 =A0 =A0 =A0 =A0 nquery (_("Because GDB is in replay mode, ch= anging the " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "value of a register wil= l make the execution " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "log unusable from this = point onward. =A0" >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Change all registers?")= ); >> > + =A0 =A0 =A0 =A0 else >> > + =A0 =A0 =A0 =A0 =A0 n =3D >> > + =A0 =A0 =A0 =A0 =A0 =A0 nquery (_("Because GDB is in replay mode, ch= anging the value " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "of a register will make= the execution log unusable " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "from this point onward.= =A0Change register %s?"), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdbarch_register_name (get_r= egcache_arch (regcache), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0regno)); >> > + >> > + =A0 =A0 =A0 =A0 if (!n) >> > + =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 /* Invalidate the value of regcache that was= set in function >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"regcache_raw_write". =A0*/ >> > + =A0 =A0 =A0 =A0 =A0 =A0 if (regno < 0) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int i; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (i =3D 0; >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0i < gdbarch_num_regs (get= _regcache_arch (regcache)); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0i++) >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache_invalidate (regcache, i= ); >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> > + =A0 =A0 =A0 =A0 =A0 =A0 else >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache_invalidate (regcache, regno); >> > + >> > + =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record canceled the operat= ion.")); >> > + =A0 =A0 =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0 =A0 /* Destroy the record from here forward. =A0*/ >> > + =A0 =A0 =A0 =A0 record_list_release_next (); >> > + =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0record_registers_change (regcache, regno); >> > + =A0 =A0} >> > + =A0record_beneath_to_store_registers (record_beneath_to_store_regist= ers_ops, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 regcache, regno); >> > +} >> > + >> > +/* Behavior is conditional on RECORD_IS_REPLAY. >> > + =A0 In replay mode, we cannot write memory unles we are willing to >> > + =A0 invalidate the record/replay log from this point forward. =A0*/ >> > + >> > +static LONGEST >> > +record_xfer_partial (struct target_ops *ops, enum target_object objec= t, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *annex, gdb_byte *= readbuf, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const gdb_byte *writebuf, ULO= NGEST offset, LONGEST len) >> > +{ >> > + =A0if (!record_gdb_operation_disable >> > + =A0 =A0 =A0&& (object =3D=3D TARGET_OBJECT_MEMORY >> > + =A0 =A0 =A0 =A0 || object =3D=3D TARGET_OBJECT_RAW_MEMORY) && writeb= uf) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (RECORD_IS_REPLAY) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 /* Let user choose if he wants to write memory or no= t. =A0*/ >> > + =A0 =A0 =A0 =A0 if (!nquery (_("Because GDB is in replay mode, writi= ng to memory " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"will make the execut= ion log unusable from this " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"point onward. =A0Wri= te memory at address 0x%s?"), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddr_nz (offset))) >> > + =A0 =A0 =A0 =A0 =A0 return -1; >> > + >> > + =A0 =A0 =A0 =A0 /* Destroy the record from here forward. =A0*/ >> > + =A0 =A0 =A0 =A0 record_list_release_next (); >> > + =A0 =A0 =A0 } >> > + >> > + =A0 =A0 =A0/* Check record_insn_num */ >> > + =A0 =A0 =A0record_check_insn_num (0); >> > + >> > + =A0 =A0 =A0/* Record registers change to list as an instruction. =A0= */ >> > + =A0 =A0 =A0record_arch_list_head =3D NULL; >> > + =A0 =A0 =A0record_arch_list_tail =3D NULL; >> > + =A0 =A0 =A0if (record_arch_list_add_mem (offset, len)) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 record_list_release (record_arch_list_tail); >> > + =A0 =A0 =A0 =A0 if (record_debug) >> > + =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Proce= ss record: failed to record " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "exe= cution log.")); >> > + =A0 =A0 =A0 =A0 return -1; >> > + =A0 =A0 =A0 } >> > + =A0 =A0 =A0if (record_arch_list_add_end ()) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 record_list_release (record_arch_list_tail); >> > + =A0 =A0 =A0 =A0 if (record_debug) >> > + =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Proce= ss record: failed to record " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "exe= cution log.")); >> > + =A0 =A0 =A0 =A0 return -1; >> > + =A0 =A0 =A0 } >> > + =A0 =A0 =A0record_list->next =3D record_arch_list_head; >> > + =A0 =A0 =A0record_arch_list_head->prev =3D record_list; >> > + =A0 =A0 =A0record_list =3D record_arch_list_tail; >> > + >> > + =A0 =A0 =A0if (record_insn_num =3D=3D record_insn_max_num && record_= insn_max_num) >> > + =A0 =A0 =A0 record_list_release_first (); >> > + =A0 =A0 =A0else >> > + =A0 =A0 =A0 record_insn_num++; >> > + =A0 =A0} >> > + >> > + =A0return record_beneath_to_xfer_partial (record_beneath_to_xfer_par= tial_ops, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 object, annex, readbuf, writebuf, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 offset, len); >> > +} >> > + >> > +/* Behavior is conditional on RECORD_IS_REPLAY. >> > + =A0 We will not actually insert or remove breakpoints when replaying, >> > + =A0 nor when recording. =A0*/ >> > + >> > +static int >> > +record_insert_breakpoint (struct bp_target_info *bp_tgt) >> > +{ >> > + =A0if (!RECORD_IS_REPLAY) >> > + =A0 =A0{ >> > + =A0 =A0 =A0struct cleanup *old_cleanups =3D record_gdb_operation_dis= able_set (); >> > + =A0 =A0 =A0int ret =3D record_beneath_to_insert_breakpoint (bp_tgt); >> > + >> > + =A0 =A0 =A0do_cleanups (old_cleanups); >> > + >> > + =A0 =A0 =A0return ret; >> > + =A0 =A0} >> > + >> > + =A0return 0; >> > +} >> > + >> > +static int >> > +record_remove_breakpoint (struct bp_target_info *bp_tgt) >> > +{ >> > + =A0if (!RECORD_IS_REPLAY) >> > + =A0 =A0{ >> > + =A0 =A0 =A0struct cleanup *old_cleanups =3D record_gdb_operation_dis= able_set (); >> > + =A0 =A0 =A0int ret =3D record_beneath_to_remove_breakpoint (bp_tgt); >> > + >> > + =A0 =A0 =A0do_cleanups (old_cleanups); >> > + >> > + =A0 =A0 =A0return ret; >> > + =A0 =A0} >> > + >> > + =A0return 0; >> > +} >> > + >> > +static int >> > +record_can_execute_reverse (void) >> > +{ >> > + =A0return 1; >> > +} >> > + >> > +static void >> > +init_record_ops (void) >> > +{ >> > + =A0record_ops.to_shortname =3D "record"; >> > + =A0record_ops.to_longname =3D "Process record and replay target"; >> > + =A0record_ops.to_doc =3D >> > + =A0 =A0"Log program while executing and replay execution from log."; >> > + =A0record_ops.to_open =3D record_open; >> > + =A0record_ops.to_close =3D record_close; >> > + =A0record_ops.to_resume =3D record_resume; >> > + =A0record_ops.to_wait =3D record_wait; >> > + =A0record_ops.to_disconnect =3D record_disconnect; >> > + =A0record_ops.to_detach =3D record_detach; >> > + =A0record_ops.to_mourn_inferior =3D record_mourn_inferior; >> > + =A0record_ops.to_kill =3D record_kill; >> > + =A0record_ops.to_create_inferior =3D find_default_create_inferior; >> > + =A0record_ops.to_store_registers =3D record_store_registers; >> > + =A0record_ops.to_xfer_partial =3D record_xfer_partial; >> > + =A0record_ops.to_insert_breakpoint =3D record_insert_breakpoint; >> > + =A0record_ops.to_remove_breakpoint =3D record_remove_breakpoint; >> > + =A0record_ops.to_can_execute_reverse =3D record_can_execute_reverse; >> > + =A0record_ops.to_stratum =3D record_stratum; >> > + =A0record_ops.to_magic =3D OPS_MAGIC; >> > +} >> > + >> > +static void >> > +show_record_debug (struct ui_file *file, int from_tty, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct cmd_list_element *c, const= char *value) >> > +{ >> > + =A0fprintf_filtered (file, _("Debugging of process record target is = %s.\n"), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 value); >> > +} >> > + >> > +/* Alias for "target record". =A0*/ >> > + >> > +static void >> > +cmd_record_start (char *args, int from_tty) >> > +{ >> > + =A0execute_command ("target record", from_tty); >> > +} >> > + >> > +/* Truncate the record log from the present point >> > + =A0 of replay until the end. =A0*/ >> > + >> > +static void >> > +cmd_record_delete (char *args, int from_tty) >> > +{ >> > + =A0if (current_target.to_stratum =3D=3D record_stratum) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (RECORD_IS_REPLAY) >> > + =A0 =A0 =A0 { >> > + =A0 =A0 =A0 =A0 if (!from_tty || query (_("Delete the log from this = point forward " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "and begin to record the running message " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = "at current PC?"))) >> > + =A0 =A0 =A0 =A0 =A0 record_list_release_next (); >> > + =A0 =A0 =A0 } >> > + =A0 =A0 =A0else >> > + =A0 =A0 =A0 =A0 printf_unfiltered (_("Already at end of record list.= \n")); >> > + >> > + =A0 =A0} >> > + =A0else >> > + =A0 =A0printf_unfiltered (_("Process record is not started.\n")); >> > +} >> > + >> > +/* Implement the "stoprecord" command. =A0*/ >> > + >> > +static void >> > +cmd_record_stop (char *args, int from_tty) >> > +{ >> > + =A0if (current_target.to_stratum =3D=3D record_stratum) >> > + =A0 =A0{ >> > + =A0 =A0 =A0if (!record_list || !from_tty || query (_("Delete recorde= d log and " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 "stop recording?"))) >> > + =A0 =A0 =A0 unpush_target (&record_ops); >> > + =A0 =A0} >> > + =A0else >> > + =A0 =A0printf_unfiltered (_("Process record is not started.\n")); >> > +} >> > + >> > +/* Set upper limit of record log size. =A0*/ >> > + >> > +static void >> > +set_record_insn_max_num (char *args, int from_tty, struct cmd_list_el= ement *c) >> > +{ >> > + =A0if (record_insn_num > record_insn_max_num && record_insn_max_num) >> > + =A0 =A0{ >> > + =A0 =A0 =A0printf_unfiltered (_("Record instructions number is bigge= r than " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"record instructi= ons max number. =A0Auto delete " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"the first ones?\= n")); >> > + >> > + =A0 =A0 =A0while (record_insn_num > record_insn_max_num) >> > + =A0 =A0 =A0 record_list_release_first (); >> > + =A0 =A0} >> > +} >> > + >> > +/* Print the current index into the record log (number of insns recor= ded >> > + =A0 so far). =A0*/ >> > + >> > +static void >> > +show_record_insn_number (char *ignore, int from_tty) >> > +{ >> > + =A0printf_unfiltered (_("Record instruction number is %d.\n"), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_insn_num); >> > +} >> > + >> > +static struct cmd_list_element *record_cmdlist, *set_record_cmdlist, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*show_rec= ord_cmdlist, *info_record_cmdlist; >> > + >> > +static void >> > +set_record_command (char *args, int from_tty) >> > +{ >> > + =A0printf_unfiltered (_("\ >> > +\"set record\" must be followed by an apporpriate subcommand.\n")); >> > + =A0help_list (set_record_cmdlist, "set record ", all_commands, gdb_s= tdout); >> > +} >> > + >> > +static void >> > +show_record_command (char *args, int from_tty) >> > +{ >> > + =A0cmd_show_list (show_record_cmdlist, from_tty, ""); >> > +} >> > + >> > +static void >> > +info_record_command (char *args, int from_tty) >> > +{ >> > + =A0cmd_show_list (info_record_cmdlist, from_tty, ""); >> > +} >> > + >> > +void >> > +_initialize_record (void) >> > +{ >> > + =A0/* Init record_first. =A0*/ >> > + =A0record_first.prev =3D NULL; >> > + =A0record_first.next =3D NULL; >> > + =A0record_first.type =3D record_end; >> > + >> > + =A0init_record_ops (); >> > + =A0add_target (&record_ops); >> > + >> > + =A0add_setshow_zinteger_cmd ("record", no_class, &record_debug, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set debugging= of record/replay feature."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show debuggin= g of record/replay feature."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("When enabled,= debugging output for " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/repl= ay feature is displayed."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, show_recor= d_debug, &setdebuglist, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &showdebuglist); >> > + >> > + =A0add_prefix_cmd ("record", class_obscure, cmd_record_start, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Abbreviated form of \"target reco= rd\" command."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist, "record ", 0, &cmdl= ist); >> > + =A0add_com_alias ("rec", "record", class_obscure, 1); >> > + =A0add_prefix_cmd ("record", class_support, set_record_command, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set record options"), &set_record= _cmdlist, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "set record ", 0, &setlist); >> > + =A0add_alias_cmd ("rec", "record", class_obscure, 1, &setlist); >> > + =A0add_prefix_cmd ("record", class_support, show_record_command, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show record options"), &show_reco= rd_cmdlist, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "show record ", 0, &showlist); >> > + =A0add_alias_cmd ("rec", "record", class_obscure, 1, &showlist); >> > + =A0add_prefix_cmd ("record", class_support, info_record_command, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Info record options"), &info_reco= rd_cmdlist, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "info record ", 0, &infolist); >> > + =A0add_alias_cmd ("rec", "record", class_obscure, 1, &infolist); >> > + >> > + >> > + =A0add_cmd ("delete", class_obscure, cmd_record_delete, >> > + =A0 =A0 =A0 =A0 =A0_("Delete the rest of execution log and start rec= ording it anew."), >> > + =A0 =A0 =A0 =A0 =A0 &record_cmdlist); >> > + =A0add_alias_cmd ("d", "delete", class_obscure, 1, &record_cmdlist); >> > + =A0add_alias_cmd ("del", "delete", class_obscure, 1, &record_cmdlist= ); >> > + >> > + =A0add_cmd ("stop", class_obscure, cmd_record_stop, >> > + =A0 =A0 =A0 =A0 =A0_("Stop the record/replay target."), >> > + =A0 =A0 =A0 =A0 =A0 &record_cmdlist); >> > + =A0add_alias_cmd ("s", "stop", class_obscure, 1, &record_cmdlist); >> > + >> > + =A0/* Record instructions number limit command. =A0*/ >> > + =A0add_setshow_boolean_cmd ("stop-at-limit", no_class, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_stop_at_= limit, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set whether r= ecord/replay stop when " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/repl= ay buffer becomes full."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show whether = record/replay stop when " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/repl= ay buffer becomes full."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Enable is def= ault value.\n" >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "When enable= d, if the record/replay buffer " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "becomes ful= l,\n" >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"ask user= what to do.\n" >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"When dis= abled, if the record/replay buffer " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "becomes ful= l,\n" >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"delete i= t and start new recording."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, NULL, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&set_record_c= mdlist, &show_record_cmdlist); >> > + =A0add_setshow_zinteger_cmd ("insn-number-max", no_class, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_insn_max= _num, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set record/re= play buffer limit."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show record/r= eplay buffer limit."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set the maxim= um number of instructions to be " >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"stored i= n the\n" >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"record/r= eplay buffer. =A0" >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Zero mea= ns unlimited (default 200000)."), >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 set_record_insn_= max_num, >> > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, &set_recor= d_cmdlist, &show_record_cmdlist); >> > + =A0add_cmd ("insn-number", class_obscure, show_record_insn_number, >> > + =A0 =A0 =A0 =A0 =A0 _("Show the current number of instructions in th= e " >> > + =A0 =A0 =A0 =A0 =A0 =A0 "record/replay buffer."), &info_record_cmdli= st); >> > +} >> > --- /dev/null >> > +++ b/record.h >> > @@ -0,0 +1,32 @@ >> > +/* Process record and replay target for GDB, the GNU debugger. >> > + >> > + =A0 Copyright (C) 2008, 2009 Free Software Foundation, Inc. >> > + >> > + =A0 This file is part of GDB. >> > + >> > + =A0 This program is free software; you can redistribute it and/or mo= dify >> > + =A0 it under the terms of the GNU General Public License as publishe= d by >> > + =A0 the Free Software Foundation; either version 3 of the License, or >> > + =A0 (at your option) any later version. >> > + >> > + =A0 This program is distributed in the hope that it will be useful, >> > + =A0 but WITHOUT ANY WARRANTY; without even the implied warranty of >> > + =A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =A0See the >> > + =A0 GNU General Public License for more details. >> > + >> > + =A0 You should have received a copy of the GNU General Public License >> > + =A0 along with this program. =A0If not, see . =A0*/ >> > + >> > +#ifndef _RECORD_H_ >> > +#define _RECORD_H_ >> > + >> > +#define RECORD_IS_USED (current_target.to_stratum =3D=3D record_strat= um) >> > + >> > +extern int record_debug; >> > + >> > +extern int record_arch_list_add_reg (struct regcache *regcache, int n= um); >> > +extern int record_arch_list_add_mem (CORE_ADDR addr, int len); >> > +extern int record_arch_list_add_end (void); >> > +extern struct cleanup *record_gdb_operation_disable_set (void); >> > + >> > +#endif /* _RECORD_H_ */ >> > >> > > > > -- > Pedro Alves >