From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30914 invoked by alias); 27 Apr 2009 21:57:33 -0000 Received: (qmail 30692 invoked by uid 22791); 27 Apr 2009 21:57:21 -0000 X-SWARE-Spam-Status: No, hits=-2.4 required=5.0 tests=AWL,BAYES_00,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 27 Apr 2009 21:54:35 +0000 Received: (qmail 3285 invoked from network); 27 Apr 2009 21:54:28 -0000 Received: from unknown (HELO orlando) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 27 Apr 2009 21:54:28 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: Re: [RFA] Submit process record and replay fourth time, 3/8 Date: Mon, 27 Apr 2009 21:57:00 -0000 User-Agent: KMail/1.9.10 Cc: Hui Zhu , Marc Khouzam , Michael Snyder , Thiago Jung Bauermann , Eli Zaretskii , paawan1982@yahoo.com, Mark Kettenis References: In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Message-Id: <200904272254.26971.pedro@codesourcery.com> 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/msg00744.txt.bz2 On Monday 27 April 2009 07:00:48, Hui Zhu wrote: > Hi Pedro, >=20 > Could you please help me review this patch? Thank you very much. This version is approved. Please don't forget a ChangeLog entry thought; I don't think I saw one. >=20 > Thanks, > Hui >=20 > 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-bu= iltin.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 mod= ify > > + =A0 it under the terms of the GNU General Public License as published= 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_REVERSE) > > + > > +/* 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" and= "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 *o= ps, > > + =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_in= fo *); > > +static int (*record_beneath_to_remove_breakpoint) (struct bp_target_in= fo *); > > + > > +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_a= rch_list_add %s.\n", > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 host_address_to_string (r= ec)); > > + > > + =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 regi= ster 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_ent= ry)); > > + =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_ent= ry)); > > + =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 le= n =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_ent= ry)); > > + =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 p= revious execution " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "log entries when= record/replay buffer becomes " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "full (record sto= p-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 progra= m 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_clea= nups, 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_A= LL); > > +} > > + > > +/* 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-st= op mode " > > + =A0 =A0 =A0 =A0 =A0 =A0"(non-stop).")); > > + =A0if (target_async_permitted) > > + =A0 =A0error (_("Process record target can't debug inferior in asynch= ronous " > > + =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 sup= port " > > + =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 wan= t 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_reg= isters; > > + =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_partial; > > + =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_brea= kpoint; > > + =A0 =A0 =A0if (!record_beneath_to_remove_breakpoint) > > + =A0 =A0 =A0 record_beneath_to_remove_breakpoint =3D t->to_remove_brea= kpoint; > > + =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, pt= id, 1, > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0siggna= l); > > + =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 *sta= tus) > > +{ > > + =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_w= ait " > > + =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_wait= _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_beneat= h_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_STOPP= ED > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && status->value.sig =3D=3D TARGET_SI= GNAL_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_p= c)) > > + =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_break= =3D > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdbarch_decr_pc_after_bre= ak > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (get_regcache_arch (get_c= urrent_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 (ge= t_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_c= urrent_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 (rec= ord_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_wait= _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 p= addr_nz (tmp_pc)); > > + =A0 =A0 =A0 =A0 =A0 =A0 if (gdbarch_decr_pc_after_break (get_regcache= _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 =A0tm= p_pc + > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gd= barch_decr_pc_after_break > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(g= et_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 th= e signal. > > + =A0 =A0 =A0 =A0 And in GDB replay mode, GDB doesn't need to be in ter= minal_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 sign= al. =A0*/ > > + =A0 =A0 =A0target_terminal_ours (); > > + > > + =A0 =A0 =A0/* In EXEC_FORWARD mode, record_list points to the tail of= prev > > + =A0 =A0 =A0 =A0 instruction. =A0*/ > > + =A0 =A0 =A0if (execution_direction =3D=3D EXEC_FORWARD && record_list= ->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 h= ost_address_to_string (record_list), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 r= ecord_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_REGI= STER_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 h= ost_address_to_string (record_list), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 p= addr_nz (record_list->u.mem.addr), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 r= ecord_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, record= _list->u.mem.len)) > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: error reading m= emory 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.m= em.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_list= ->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 wr= iting 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.m= em.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_l= ist->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 h= ost_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 rec= ord_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_s= tdlog, > > + =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 (regcache= ); > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (breakpoint_inserted_here_p (tmp_p= c)) > > + =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_s= tdlog, > > + =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_bre= ak (get_regcache_arch (regcache)) > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && execution_directio= n =3D=3D EXEC_FORWARD > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && !record_resume_ste= p) > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache_write_pc (regcac= he, > > + =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->prev; > > + =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->next; > > + =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_tty) > > +{ > > + =A0if (record_debug) > > + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: record_discon= nect\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_detach= \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 instructi= on. =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 (reg= cache)); 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 ex= ecution 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 *regca= che, > > + =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 n= ot. =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, cha= nging the " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "value of a register will= make the execution " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "log unusable from this p= oint 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, cha= nging 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_re= gcache_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 operati= on.")); > > + =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_registe= rs_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 object, > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *annex, gdb_byte *r= eadbuf, > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const gdb_byte *writebuf, ULON= GEST 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) && writebu= f) > > + =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 not= . =A0*/ > > + =A0 =A0 =A0 =A0 if (!nquery (_("Because GDB is in replay mode, writin= g to memory " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"will make the executi= on log unusable from this " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"point onward. =A0Writ= e 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 _("Proces= s record: failed to record " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "exec= ution 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 _("Proces= s record: failed to record " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "exec= ution 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_i= nsn_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_part= ial_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_disa= ble_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_disa= ble_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 p= oint 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 recorded= 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_ele= ment *c) > > +{ > > + =A0if (record_insn_num > record_insn_max_num && record_insn_max_num) > > + =A0 =A0{ > > + =A0 =A0 =A0printf_unfiltered (_("Record instructions number is bigger= than " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"record instructio= ns 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 record= ed > > + =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_reco= rd_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_st= dout); > > +} > > + > > +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 debugging= 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/repla= y feature is displayed."), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, show_record= _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 recor= d\" command."), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist, "record ", 0, &cmdli= st); > > + =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_recor= d_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_recor= d_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 reco= rding 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_l= imit, > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set whether re= cord/replay stop when " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/repla= y buffer becomes full."), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show whether r= ecord/replay stop when " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/repla= y buffer becomes full."), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Enable is defa= ult value.\n" > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "When enabled= , if the record/replay buffer " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "becomes full= ,\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 disa= bled, if the record/replay buffer " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "becomes full= ,\n" > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"delete it= 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_cm= dlist, &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/rep= lay buffer limit."), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show record/re= play buffer limit."), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set the maximu= m number of instructions to be " > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"stored in= the\n" > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"record/re= play buffer. =A0" > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Zero mean= s unlimited (default 200000)."), > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 set_record_insn_m= ax_num, > > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, &set_record= _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 the= " > > + =A0 =A0 =A0 =A0 =A0 =A0 "record/replay buffer."), &info_record_cmdlis= t); > > +} > > --- /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 mod= ify > > + =A0 it under the terms of the GNU General Public License as published= 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_stratu= m) > > + > > +extern int record_debug; > > + > > +extern int record_arch_list_add_reg (struct regcache *regcache, int nu= m); > > +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_ */ > > >=20 --=20 Pedro Alves