From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31408 invoked by alias); 27 Apr 2009 06:01:28 -0000 Received: (qmail 29049 invoked by uid 22791); 27 Apr 2009 06:01:19 -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.185) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 27 Apr 2009 06:00:52 +0000 Received: by ti-out-0910.google.com with SMTP id a1so267978tib.12 for ; Sun, 26 Apr 2009 23:00:48 -0700 (PDT) MIME-Version: 1.0 Received: by 10.110.14.12 with SMTP id 12mr387897tin.32.1240812048212; Sun, 26 Apr 2009 23:00:48 -0700 (PDT) In-Reply-To: References: Date: Mon, 27 Apr 2009 06:01:00 -0000 Message-ID: Subject: Re: [RFA] Submit process record and replay fourth time, 3/8 From: Hui Zhu To: "gdb-patches@sourceware.org" Cc: Pedro Alves , 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/msg00727.txt.bz2 Hi Pedro, Could you please help me review this patch? 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-buil= tin.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 modify > + =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, in= t, > + =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_info= *); > +static int (*record_beneath_to_remove_breakpoint) (struct bp_target_info= *); > + > +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_arc= h_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 regist= er 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_entry= )); > + =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 ad= dr =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_entry= )); > + =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: er= ror reading memory at " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr =3D 0x%s len = =3D %d.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddr_nz (addr), le= n); > + =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_entry= )); > + =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 pre= vious execution " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "log entries when r= ecord/replay buffer becomes " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "full (record stop-= 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 program = 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_cleanu= ps, 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_re= ad_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_nu= m) > + =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-stop= mode " > + =A0 =A0 =A0 =A0 =A0 =A0"(non-stop).")); > + =A0if (target_async_permitted) > + =A0 =A0error (_("Process record target can't debug inferior in asynchro= nous " > + =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 suppo= rt " > + =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 want = 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_regis= ters; > + =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_breakp= oint; > + =A0 =A0 =A0if (!record_beneath_to_remove_breakpoint) > + =A0 =A0 =A0 record_beneath_to_remove_breakpoint =3D t->to_remove_breakp= oint; > + =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, ptid= , 1, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0siggnal); > + =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 *statu= s) > +{ > + =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_wai= t " > + =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_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 =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_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 ptid, status); > + > + =A0 =A0 =A0 =A0 =A0 =A0 if (status->kind =3D=3D TARGET_WAITKIND_STOPPED > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && status->value.sig =3D=3D TARGET_SIGN= AL_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_break = =3D > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdbarch_decr_pc_after_break > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (get_regcache_arch (get_cur= rent_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 (get_= 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_cur= rent_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 (recor= d_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_c= leanups, 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 "Pr= ocess record: break at 0x%s.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pad= dr_nz (tmp_pc)); > + =A0 =A0 =A0 =A0 =A0 =A0 if (gdbarch_decr_pc_after_break (get_regcache_a= rch (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 =A0tmp_= pc + > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gdba= rch_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 the = signal. > + =A0 =A0 =A0 =A0 And in GDB replay mode, GDB doesn't need to be in termi= nal_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 signal= . =A0*/ > + =A0 =A0 =A0target_terminal_ours (); > + > + =A0 =A0 =A0/* In EXEC_FORWARD mode, record_list points to the tail of p= rev > + =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_li= st->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_li= st. =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 "Pr= ocess record: record_reg %s to " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "in= ferior num =3D %d.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hos= t_address_to_string (record_list), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rec= ord_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 =A0= record_list->u.reg.val); > + =A0 =A0 =A0 =A0 =A0 =A0 memcpy (record_list->u.reg.val, reg, MAX_REGIST= ER_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.le= n); > + =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 "Pr= ocess record: record_mem %s to " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "in= ferior 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 hos= t_address_to_string (record_list), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pad= dr_nz (record_list->u.mem.addr), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rec= ord_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_l= ist->u.mem.len)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: error reading mem= ory 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_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 writ= ing 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_lis= t->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 "Pr= ocess record: record_end %s to " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "in= ferior.\n", > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 hos= t_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 recor= d_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 re= cord_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 th= e 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_std= log, > + =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_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_std= log, > + =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_break= (get_regcache_arch (regcache)) > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && execution_direction = =3D=3D EXEC_FORWARD > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && !record_resume_step) > + =A0 =A0 =A0 =A0 =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 =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_disconne= ct\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 "re= cord_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 instruction= . =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 (regca= che)); 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 exec= ution 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 lo= g.")); > + =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_nu= m) > + =A0 =A0record_list_release_first (); > + =A0else > + =A0 =A0record_insn_num++; > +} > + > +static void > +record_store_registers (struct target_ops *ops, struct regcache *regcach= e, > + =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, chang= ing the " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "value of a register will m= ake the execution " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "log unusable from this poi= nt 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, chang= ing the value " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "of a register will make th= e 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_regc= ache_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 se= t 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_re= gcache_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 operation= .")); > + =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_registers= _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 *rea= dbuf, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const gdb_byte *writebuf, ULONGE= ST 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) && writebuf) > + =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, writing = to memory " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"will make the execution= log unusable from this " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"point onward. =A0Write = 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 _("Process = record: failed to record " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "execut= ion 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 _("Process = record: failed to record " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "execut= ion 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_ins= n_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_partia= l_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_disabl= e_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_disabl= e_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 ch= ar *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 poi= nt forward " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "an= d 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 l= og 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_eleme= nt *c) > +{ > + =A0if (record_insn_num > record_insn_max_num && record_insn_max_num) > + =A0 =A0{ > + =A0 =A0 =A0printf_unfiltered (_("Record instructions number is bigger t= han " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"record instructions= 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 recorded > + =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_record= _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_stdo= ut); > +} > + > +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 o= f record/replay feature."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("When enabled, de= bugging output for " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/replay = feature is displayed."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, show_record_d= ebug, &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 record\= " command."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist, "record ", 0, &cmdlist= ); > + =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_cm= dlist, > + =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_record_= 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_record_= 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 record= ing 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_lim= it, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set whether reco= rd/replay stop when " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/replay = buffer becomes full."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show whether rec= ord/replay stop when " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "record/replay = buffer becomes full."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Enable is defaul= t 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 wh= at to do.\n" > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"When disabl= ed, 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 a= nd 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_cmdl= ist, &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_nu= m, > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set record/repla= y buffer limit."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Show record/repl= ay buffer limit."), > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Set the maximum = number of instructions to be " > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"stored in t= he\n" > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"record/repl= ay buffer. =A0" > + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Zero means = 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_record_c= mdlist, &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_cmdlist); > +} > --- /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 modify > + =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_stratum) > + > +extern int record_debug; > + > +extern int record_arch_list_add_reg (struct regcache *regcache, int num); > +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_ */ >