From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2091 invoked by alias); 25 Aug 2009 06:53:50 -0000 Received: (qmail 2072 invoked by uid 22791); 25 Aug 2009 06:53:42 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL,BAYES_00,SARE_MSGID_LONG40,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail-pz0-f198.google.com (HELO mail-pz0-f198.google.com) (209.85.222.198) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 25 Aug 2009 06:53:28 +0000 Received: by pzk36 with SMTP id 36so1422439pzk.12 for ; Mon, 24 Aug 2009 23:53:26 -0700 (PDT) MIME-Version: 1.0 Received: by 10.142.209.20 with SMTP id h20mr346545wfg.36.1251183206155; Mon, 24 Aug 2009 23:53:26 -0700 (PDT) In-Reply-To: <4A92D317.9010002@vmware.com> References: <83ws5gm30b.fsf@gnu.org> <4A7C625B.8080005@vmware.com> <4A7F5410.4000400@vmware.com> <4A91CEEC.5000802@vmware.com> <4A92D317.9010002@vmware.com> From: Hui Zhu Date: Tue, 25 Aug 2009 08:47:00 -0000 Message-ID: Subject: Re: [RFA/RFC] Add dump and load command to process record and replay To: Michael Snyder Cc: Eli Zaretskii , "gdb-patches@sourceware.org" 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-08/txt/msg00409.txt.bz2 On Tue, Aug 25, 2009 at 01:51, Michael Snyder wrote: > Hui Zhu wrote: >> >> On Mon, Aug 24, 2009 at 07:21, Michael Snyder wrote: >>> >>> Hui Zhu wrote: >>> >>>> Hi Michael, >>>> >>>> I make a new version patch. =A0It has a lot of changes. >>>> Remove record_core and add a new target record_core for core target to >>>> make the code more clear. >>>> Make the load together with record_open. >>>> >>>> Please help me review it. >>> >>> Hi Hui, >>> >>> In this review, I'm going to comment only on the parts of the >>> patch that relate to the record_core_ops (ie. pushing the >>> record stratum on top of the core file stratum). >>> >>> Those parts of the patch are much improved. =A0I like this >>> version a lot better. =A0Thanks for reworking it. >>> >> >> >> Hi Michael, >> >> Thanks for your review. =A0I make a new patch that update the memset code >> to: > > Way cool, thanks! > > Now I can comment on the dump/load part of the patch. > It does not seem as if previous issues have been addressed: > 1) Core file and record file are separate, no way to verify > =A0 that they correspond to each other. > 2) Previous log not cleared when loading a new log. For it, I think we don't need worry about it. Because I make the record load together with record_open. So each time when we load record, the record list is empty. > > Have you considered combining this patch with the idea that I > proposed -- storing the record log in the core file? =A0Seems like > that would be very easy now -- gdb already has the core file open, > and there is a global pointer to the BFD. > See gdbcore.h:extern bfd* core_bfd; Cool. If we just want record_core_ops support load, we can remove the cmd "record load". :) > > In fact, just for fun, I've merged the two patches in my > local tree. =A0It seems to work quite well. =A0I can just post > it here if you like, or here's a hint to show you how it goes: Why not? Please post it. I can not wait to try it. :) Thanks, Hui > > static void > record_load (void) > { > =A0int recfd; > =A0uint32_t magic; > =A0struct cleanup *old_cleanups2; > =A0struct record_entry *rec; > =A0int insn_number =3D 0; > =A0asection *osec; > =A0void nullify_last_target_wait_ptid (void); > > =A0/* We load the execution log from the open core bfd, > =A0 =A0 if there is one. =A0*/ > =A0if (core_bfd =3D=3D NULL) > =A0 =A0return; > > =A0if (record_debug) > =A0 =A0fprintf_filtered (gdb_stdlog, > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Restoring recording from co= re file.\n")); > > =A0/* Now need to find our special note section. =A0*/ > =A0osec =3D bfd_get_section_by_name (core_bfd, "null0"); > > >> =A0 =A0 =A0 =A0 =A0 =A0if (target_read_memory (entry->u.mem.addr, mem, >> entry->u.mem.len)) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.mem_entry_not_accessib= le =3D 1; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0warning (_("Process record: error rea= ding memory at " >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr =3D %s len= =3D %d."), >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (gdbarch, e= ntry->u.mem.addr), >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 entry->u.mem.len); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0else >> =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (target_write_memory (entry->u.mem.add= r, >> entry->u.mem.val, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 entry->u.mem.len)) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.mem_entry_not_= accessible =3D 1; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0warning (_("Process record: e= rror writing memory at " >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr = =3D %s len =3D %d."), >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (gd= barch, entry->u.mem.addr), >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 entry->u.mem= .len); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memcpy (entry->u.mem.val, mem, entry-= >u.mem.len); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> >> Please help me review it. >> >> Thanks, >> Hui >> >> --- >> =A0record.c | =A0951 >> ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- >> =A01 file changed, 825 insertions(+), 126 deletions(-) >> >> --- a/record.c >> +++ b/record.c >> @@ -23,15 +23,23 @@ >> =A0#include "gdbthread.h" >> =A0#include "event-top.h" >> =A0#include "exceptions.h" >> +#include "completer.h" >> +#include "arch-utils.h" >> +#include "gdbcore.h" >> +#include "exec.h" >> =A0#include "record.h" >> >> +#include >> =A0#include >> +#include >> >> =A0#define DEFAULT_RECORD_INSN_MAX_NUM =A0 =A0200000 >> >> =A0#define RECORD_IS_REPLAY \ >> =A0 =A0 =A0(record_list->next || execution_direction =3D=3D EXEC_REVERSE) >> >> +#define RECORD_FILE_MAGIC =A0 =A0 =A0htonl(0x20090726) >> + >> =A0/* These are the core struct of record function. >> >> =A0 =A0An record_entry is a record of the value change of a register >> @@ -78,9 +86,22 @@ struct record_entry >> =A0 } u; >> =A0}; >> >> +struct record_core_buf_entry >> +{ >> + =A0struct record_core_buf_entry *prev; >> + =A0struct target_section *p; >> + =A0bfd_byte *buf; >> +}; >> + >> =A0/* This is the debug switch for process record. =A0*/ >> =A0int record_debug =3D 0; >> >> +/* Record buf with core target. =A0*/ >> +static gdb_byte *record_core_regbuf =3D NULL; >> +static struct target_section *record_core_start; >> +static struct target_section *record_core_end; >> +static struct record_core_buf_entry *record_core_buf_list =3D NULL; >> + >> =A0/* These list is for execution log. =A0*/ >> =A0static struct record_entry record_first; >> =A0static struct record_entry *record_list =3D &record_first; >> @@ -94,6 +115,7 @@ static int record_insn_num =3D 0; >> >> =A0/* The target_ops of process record. =A0*/ >> =A0static struct target_ops record_ops; >> +static struct target_ops record_core_ops; >> >> =A0/* The beneath function pointers. =A0*/ >> =A0static struct target_ops *record_beneath_to_resume_ops; >> @@ -169,7 +191,7 @@ record_list_release_next (void) >> =A0} >> >> =A0static void >> -record_list_release_first (void) >> +record_list_release_first_insn (void) >> =A0{ >> =A0 struct record_entry *tmp =3D NULL; >> =A0 enum record_type type; >> @@ -340,30 +362,30 @@ record_check_insn_num (int set_terminal) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0if (q) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_stop_at_limit =3D 0; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: inferior program= stopped.")); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: stoped by user."= )); >> =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0} >> =A0 =A0 } >> =A0} >> >> +static void >> +record_arch_list_cleanups (void *ignore) >> +{ >> + =A0record_list_release (record_arch_list_tail); >> +} >> + >> =A0/* Before inferior step (when GDB record the running message, inferior >> =A0 =A0only can step), GDB will call this function to record the values = to >> =A0 =A0record_list. =A0This function will call gdbarch_process_record to >> =A0 =A0record the running message of inferior and set them to >> =A0 =A0record_arch_list, and add it to record_list. =A0*/ >> >> -static void >> -record_message_cleanups (void *ignore) >> -{ >> - =A0record_list_release (record_arch_list_tail); >> -} >> - >> =A0static int >> =A0record_message (void *args) >> =A0{ >> =A0 int ret; >> =A0 struct regcache *regcache =3D args; >> - =A0struct cleanup *old_cleanups =3D make_cleanup (record_message_clean= ups, >> 0); >> + =A0struct cleanup *old_cleanups =3D make_cleanup (record_arch_list_cle= anups, >> 0); >> >> =A0 record_arch_list_head =3D NULL; >> =A0 record_arch_list_tail =3D NULL; >> @@ -386,7 +408,7 @@ record_message (void *args) >> =A0 record_list =3D record_arch_list_tail; >> >> =A0 if (record_insn_num =3D=3D record_insn_max_num && record_insn_max_nu= m) >> - =A0 =A0record_list_release_first (); >> + =A0 =A0record_list_release_first_insn (); >> =A0 else >> =A0 =A0 record_insn_num++; >> >> @@ -416,13 +438,291 @@ record_gdb_operation_disable_set (void) >> =A0 return old_cleanups; >> =A0} >> >> +static inline void >> +record_exec_entry (struct regcache *regcache, struct gdbarch *gdbarch, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct record_entry *entry) >> +{ >> + =A0switch (entry->type) >> + =A0 =A0{ >> + =A0 =A0case record_reg: /* reg */ >> + =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0gdb_byte reg[MAX_REGISTER_SIZE]; >> + >> + =A0 =A0 =A0 =A0if (record_debug > 1) >> + =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Process re= cord: record_reg %s to " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"inferior n= um =3D %d.\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0host_addres= s_to_string (entry), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0entry->u.re= g.num); >> + >> + =A0 =A0 =A0 =A0regcache_cooked_read (regcache, entry->u.reg.num, reg); >> + =A0 =A0 =A0 =A0regcache_cooked_write (regcache, entry->u.reg.num, >> entry->u.reg.val); >> + =A0 =A0 =A0 =A0memcpy (entry->u.reg.val, reg, MAX_REGISTER_SIZE); >> + =A0 =A0 =A0} >> + =A0 =A0 =A0break; >> + >> + =A0 =A0case record_mem: /* mem */ >> + =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0if (!record_list->u.mem.mem_entry_not_accessible) >> + =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0gdb_byte *mem =3D alloca (entry->u.mem.len); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0if (record_debug > 1) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_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 %s len =3D %d.\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0hos= t_address_to_string (entry), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pad= dress (gdbarch, entry->u.mem.addr), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rec= ord_list->u.mem.len); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0if (target_read_memory (entry->u.mem.addr, mem, >> entry->u.mem.len)) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.mem_entry_not_access= ible =3D 1; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0warning (_("Process record: error r= eading memory at " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr =3D %s l= en =3D %d."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (gdbarch,= entry->u.mem.addr), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 entry->u.mem.len); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (target_write_memory (entry->u.mem.a= ddr, >> entry->u.mem.val, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 entry->u.mem.len)) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.mem_entry_no= t_accessible =3D 1; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0warning (_("Process record:= error writing memory at >> " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "addr = =3D %s len =3D %d."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (= gdbarch, entry->u.mem.addr), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 entry->u.m= em.len); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memcpy (entry->u.mem.val, mem, entr= y->u.mem.len); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0} >> + =A0 =A0 =A0break; >> + =A0 =A0} >> +} >> + >> +static inline void >> +record_read_dump (char *recfilename, int fildes, void *buf, size_t nbyt= e) >> +{ >> + =A0if (read (fildes, buf, nbyte) !=3D nbyte) >> + =A0 =A0error (_("Failed to read dump of execution records in '%s'."), >> + =A0 =A0 =A0 =A0 =A0 recfilename); >> +} >> + >> =A0static void >> -record_open (char *name, int from_tty) >> +record_fd_cleanups (void *recfdp) >> =A0{ >> - =A0struct target_ops *t; >> + =A0int recfd =3D *(int *) recfdp; >> + =A0close (recfd); >> +} >> >> - =A0if (record_debug) >> - =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: record_open\n"= ); >> +/* Load the execution log from a file. =A0*/ >> + >> +static void >> +record_load (char *name) >> +{ >> + =A0int recfd; >> + =A0uint32_t magic; >> + =A0struct cleanup *old_cleanups; >> + =A0struct cleanup *old_cleanups2; >> + =A0struct record_entry *rec; >> + =A0int insn_number =3D 0; >> + >> + =A0if (!name || (name && !*name)) >> + =A0 =A0return; >> + >> + =A0/* Open the load file. =A0*/ >> + =A0recfd =3D open (name, O_RDONLY | O_BINARY); >> + =A0if (recfd < 0) >> + =A0 =A0error (_("Failed to open '%s' for loading execution records: %s= "), >> + =A0 =A0 =A0 =A0 =A0 name, strerror (errno)); >> + =A0old_cleanups =3D make_cleanup (record_fd_cleanups, &recfd); >> + >> + =A0/* Check the magic code. =A0*/ >> + =A0record_read_dump (name, recfd, &magic, 4); >> + =A0if (magic !=3D RECORD_FILE_MAGIC) >> + =A0 =A0error (_("'%s' is not a valid dump of execution records."), nam= e); >> + >> + =A0/* Load the entries in recfd to the record_arch_list_head and >> + =A0 =A0 record_arch_list_tail. =A0*/ >> + =A0record_arch_list_head =3D NULL; >> + =A0record_arch_list_tail =3D NULL; >> + =A0old_cleanups2 =3D make_cleanup (record_arch_list_cleanups, 0); >> + >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0int ret; >> + =A0 =A0 =A0uint8_t tmpu8; >> + =A0 =A0 =A0uint64_t tmpu64; >> + >> + =A0 =A0 =A0ret =3D read (recfd, &tmpu8, 1); >> + =A0 =A0 =A0if (ret < 0) >> + =A0 =A0 =A0 =A0error (_("Failed to read dump of execution records in '= %s'."), >> name); >> + =A0 =A0 =A0if (ret =3D=3D 0) >> + =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0switch (tmpu8) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0case record_reg: /* reg */ >> + =A0 =A0 =A0 =A0 =A0rec =3D (struct record_entry *) xmalloc (sizeof (st= ruct >> record_entry)); >> + =A0 =A0 =A0 =A0 =A0rec->u.reg.val =3D (gdb_byte *) xmalloc (MAX_REGIST= ER_SIZE); >> + =A0 =A0 =A0 =A0 =A0rec->prev =3D NULL; >> + =A0 =A0 =A0 =A0 =A0rec->next =3D NULL; >> + =A0 =A0 =A0 =A0 =A0rec->type =3D record_reg; >> + >> + =A0 =A0 =A0 =A0 =A0/* Get num. =A0*/ >> + =A0 =A0 =A0 =A0 =A0record_read_dump (name, recfd, &tmpu64, 8); >> + =A0 =A0 =A0 =A0 =A0if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) >> + =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D bswap_64 (tmpu64); >> + =A0 =A0 =A0 =A0 =A0rec->u.reg.num =3D tmpu64; >> + >> + =A0 =A0 =A0 =A0 =A0/* Get val. =A0*/ >> + =A0 =A0 =A0 =A0 =A0record_read_dump (name, recfd, rec->u.reg.val, >> MAX_REGISTER_SIZE); >> + >> + =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, _("\ >> +Reading register %d (1 plus 8 plus %d bytes)\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rec->u.= reg.num, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0MAX_REG= ISTER_SIZE); >> + >> + =A0 =A0 =A0 =A0 =A0record_arch_list_add (rec); >> + =A0 =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0 =A0case record_mem: /* mem */ >> + =A0 =A0 =A0 =A0 =A0rec =3D (struct record_entry *) xmalloc (sizeof (st= ruct >> record_entry)); >> + =A0 =A0 =A0 =A0 =A0rec->prev =3D NULL; >> + =A0 =A0 =A0 =A0 =A0rec->next =3D NULL; >> + =A0 =A0 =A0 =A0 =A0rec->type =3D record_mem; >> + >> + =A0 =A0 =A0 =A0 =A0/* Get addr. =A0*/ >> + =A0 =A0 =A0 =A0 =A0record_read_dump (name, recfd, &tmpu64, 8); >> + =A0 =A0 =A0 =A0 =A0if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) >> + =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D bswap_64 (tmpu64); >> + =A0 =A0 =A0 =A0 =A0rec->u.mem.addr =3D tmpu64; >> + >> + =A0 =A0 =A0 =A0 =A0/* Get len. =A0*/ >> + =A0 =A0 =A0 =A0 =A0record_read_dump (name, recfd, &tmpu64, 8); >> + =A0 =A0 =A0 =A0 =A0if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) >> + =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D bswap_64 (tmpu64); >> + =A0 =A0 =A0 =A0 =A0rec->u.mem.len =3D tmpu64; >> + =A0 =A0 =A0 =A0 =A0rec->u.mem.mem_entry_not_accessible =3D 0; >> + =A0 =A0 =A0 =A0 =A0rec->u.mem.val =3D (gdb_byte *) xmalloc (rec->u.mem= .len); >> + >> + =A0 =A0 =A0 =A0 =A0/* Get val. =A0*/ >> + =A0 =A0 =A0 =A0 =A0record_read_dump (name, recfd, rec->u.mem.val, rec-= >u.mem.len); >> + >> + =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, _("\ >> +Reading memory %s (1 plus 8 plus 8 bytes plus %d bytes)\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0paddress (get_current_arch (), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rec->u.mem.addr), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0rec->u.mem.len); >> + >> + =A0 =A0 =A0 =A0 =A0record_arch_list_add (rec); >> + =A0 =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0 =A0case record_end: /* end */ >> + =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Read= ing record_end (1 byte)\n")); >> + >> + =A0 =A0 =A0 =A0 =A0rec =3D (struct record_entry *) xmalloc (sizeof (st= ruct >> record_entry)); >> + =A0 =A0 =A0 =A0 =A0rec->prev =3D NULL; >> + =A0 =A0 =A0 =A0 =A0rec->next =3D NULL; >> + =A0 =A0 =A0 =A0 =A0rec->type =3D record_end; >> + =A0 =A0 =A0 =A0 =A0record_arch_list_add (rec); >> + =A0 =A0 =A0 =A0 =A0insn_number ++; >> + =A0 =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0 =A0default: >> + =A0 =A0 =A0 =A0 =A0error (_("Format of '%s' is not right."), name); >> + =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0discard_cleanups (old_cleanups2); >> + >> + =A0/* Add record_arch_list_head to the end of record list. =A0*/ >> + =A0for (rec =3D record_list; rec->next; rec =3D rec->next); >> + =A0rec->next =3D record_arch_list_head; >> + =A0record_arch_list_head->prev =3D rec; >> + >> + =A0/* Update record_insn_num and record_insn_max_num. =A0*/ >> + =A0record_insn_num +=3D insn_number; >> + =A0if (record_insn_num > record_insn_max_num) >> + =A0 =A0{ >> + =A0 =A0 =A0record_insn_max_num =3D record_insn_num; >> + =A0 =A0 =A0warning (_("Auto increase record/replay buffer limit to %d.= "), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_insn_max_num); >> + =A0 =A0} >> + >> + =A0do_cleanups (old_cleanups); >> + >> + =A0/* Succeeded. =A0*/ >> + =A0fprintf_filtered (gdb_stdout, "Loaded recfile %s.\n", name); >> +} >> + >> +static struct target_ops *tmp_to_resume_ops; >> +static void (*tmp_to_resume) (struct target_ops *, ptid_t, int, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enum target= _signal); >> +static struct target_ops *tmp_to_wait_ops; >> +static ptid_t (*tmp_to_wait) (struct target_ops *, ptid_t, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct targ= et_waitstatus *, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int); >> +static struct target_ops *tmp_to_store_registers_ops; >> +static void (*tmp_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 struct regcache *, >> + =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 *tmp_to_xfer_partial_ops; >> +static LONGEST (*tmp_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 enum target_object object, >> + =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 gdb_byte *readbuf, >> + =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 ULONGEST offset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 LONGEST len); >> +static int (*tmp_to_insert_breakpoint) (struct gdbarch *, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0struct bp_target_info *); >> +static int (*tmp_to_remove_breakpoint) (struct gdbarch *, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0struct bp_target_info *); >> + >> +static void >> +record_core_open_1 (char *name, int from_tty) >> +{ >> + =A0struct regcache *regcache =3D get_current_regcache (); >> + =A0int regnum =3D gdbarch_num_regs (get_regcache_arch (regcache)); >> + =A0int i; >> + >> + =A0if (!name || (name && !*name)) >> + =A0 =A0error (_("Argument for gdb record filename required.\n")); >> + >> + =A0/* Get record_core_regbuf. =A0*/ >> + =A0target_fetch_registers (regcache, -1); >> + =A0record_core_regbuf =3D xmalloc (MAX_REGISTER_SIZE * regnum); >> + =A0for (i =3D 0; i < regnum; i ++) >> + =A0 =A0regcache_raw_collect (regcache, i, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_core_regbuf = + MAX_REGISTER_SIZE * i); >> + >> + =A0/* Get record_core_start and record_core_end. =A0*/ >> + =A0if (build_section_table (core_bfd, &record_core_start, >> &record_core_end)) >> + =A0 =A0{ >> + =A0 =A0 =A0xfree (record_core_regbuf); >> + =A0 =A0 =A0record_core_regbuf =3D NULL; >> + =A0 =A0 =A0error (_("\"%s\": Can't find sections: %s"), >> + =A0 =A0 =A0 =A0 =A0 =A0 bfd_get_filename (core_bfd), bfd_errmsg (bfd_g= et_error ())); >> + =A0 =A0} >> + >> + =A0push_target (&record_core_ops); >> +} >> + >> +static void >> +record_open_1 (char *name, int from_tty) >> +{ >> + =A0struct target_ops *t; >> >> =A0 /* check exec */ >> =A0 if (!target_has_execution) >> @@ -438,6 +738,28 @@ record_open (char *name, int from_tty) >> =A0 =A0 error (_("Process record: the current architecture doesn't suppo= rt " >> =A0 =A0 =A0 =A0 =A0 =A0 "record function.")); >> >> + =A0if (!tmp_to_resume) >> + =A0 =A0error (_("Process record can't get to_resume.")); >> + =A0if (!tmp_to_wait) >> + =A0 =A0error (_("Process record can't get to_wait.")); >> + =A0if (!tmp_to_store_registers) >> + =A0 =A0error (_("Process record can't get to_store_registers.")); >> + =A0if (!tmp_to_insert_breakpoint) >> + =A0 =A0error (_("Process record can't get to_insert_breakpoint.")); >> + =A0if (!tmp_to_remove_breakpoint) >> + =A0 =A0error (_("Process record can't get to_remove_breakpoint.")); >> + >> + =A0push_target (&record_ops); >> +} >> + >> +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 if record target is already running. =A0*/ >> =A0 if (current_target.to_stratum =3D=3D record_stratum) >> =A0 =A0 { >> @@ -447,70 +769,102 @@ record_open (char *name, int from_tty) >> =A0 =A0 =A0 =A0return; >> =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/* Reset the tmp beneath pointers. =A0*/ >> + =A0tmp_to_resume_ops =3D NULL; >> + =A0tmp_to_resume =3D NULL; >> + =A0tmp_to_wait_ops =3D NULL; >> + =A0tmp_to_wait =3D NULL; >> + =A0tmp_to_store_registers_ops =3D NULL; >> + =A0tmp_to_store_registers =3D NULL; >> + =A0tmp_to_xfer_partial_ops =3D NULL; >> + =A0tmp_to_xfer_partial =3D NULL; >> + =A0tmp_to_insert_breakpoint =3D NULL; >> + =A0tmp_to_remove_breakpoint =3D NULL; >> >> =A0 /* Set the beneath function pointers. =A0*/ >> =A0 for (t =3D current_target.beneath; t !=3D NULL; t =3D t->beneath) >> =A0 =A0 { >> - =A0 =A0 =A0if (!record_beneath_to_resume) >> + =A0 =A0 =A0if (!tmp_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 tmp_to_resume =3D t->to_resume; >> + =A0 =A0 =A0 =A0 tmp_to_resume_ops =3D t; >> =A0 =A0 =A0 =A0 } >> - =A0 =A0 =A0if (!record_beneath_to_wait) >> + =A0 =A0 =A0if (!tmp_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 tmp_to_wait =3D t->to_wait; >> + =A0 =A0 =A0 =A0 tmp_to_wait_ops =3D t; >> =A0 =A0 =A0 =A0 } >> - =A0 =A0 =A0if (!record_beneath_to_store_registers) >> + =A0 =A0 =A0if (!tmp_to_store_registers) >> =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 record_beneath_to_store_registers =3D t->to_store_regi= sters; >> - =A0 =A0 =A0 =A0 record_beneath_to_store_registers_ops =3D t; >> + =A0 =A0 =A0 =A0 tmp_to_store_registers =3D t->to_store_registers; >> + =A0 =A0 =A0 =A0 tmp_to_store_registers_ops =3D t; >> =A0 =A0 =A0 =A0 } >> - =A0 =A0 =A0if (!record_beneath_to_xfer_partial) >> + =A0 =A0 =A0if (!tmp_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 tmp_to_xfer_partial =3D t->to_xfer_partial; >> + =A0 =A0 =A0 =A0 tmp_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_break= point; >> - =A0 =A0 =A0if (!record_beneath_to_remove_breakpoint) >> - =A0 =A0 =A0 record_beneath_to_remove_breakpoint =3D t->to_remove_break= point; >> + =A0 =A0 =A0if (!tmp_to_insert_breakpoint) >> + =A0 =A0 =A0 tmp_to_insert_breakpoint =3D t->to_insert_breakpoint; >> + =A0 =A0 =A0if (!tmp_to_remove_breakpoint) >> + =A0 =A0 =A0 tmp_to_remove_breakpoint =3D t->to_remove_breakpoint; >> =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) >> + =A0if (!tmp_to_xfer_partial) >> =A0 =A0 error (_("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); >> + =A0if (current_target.to_stratum =3D=3D core_stratum) >> + =A0 =A0record_core_open_1 (name, from_tty); >> + =A0else >> + =A0 =A0record_open_1 (name, from_tty); >> >> =A0 /* Reset */ >> =A0 record_insn_num =3D 0; >> =A0 record_list =3D &record_first; >> =A0 record_list->next =3D NULL; >> + >> + =A0/* Set the tmp beneath pointers to beneath pointers. =A0*/ >> + =A0record_beneath_to_resume_ops =3D tmp_to_resume_ops; >> + =A0record_beneath_to_resume =3D tmp_to_resume; >> + =A0record_beneath_to_wait_ops =3D tmp_to_wait_ops; >> + =A0record_beneath_to_wait =3D tmp_to_wait; >> + =A0record_beneath_to_store_registers_ops =3D tmp_to_store_registers_op= s; >> + =A0record_beneath_to_store_registers =3D tmp_to_store_registers; >> + =A0record_beneath_to_xfer_partial_ops =3D tmp_to_xfer_partial_ops; >> + =A0record_beneath_to_xfer_partial =3D tmp_to_xfer_partial; >> + =A0record_beneath_to_insert_breakpoint =3D tmp_to_insert_breakpoint; >> + =A0record_beneath_to_remove_breakpoint =3D tmp_to_remove_breakpoint; >> + >> + =A0/* Load if there is argument. =A0*/ >> + =A0record_load (name); >> =A0} >> >> =A0static void >> =A0record_close (int quitting) >> =A0{ >> + =A0struct record_core_buf_entry *entry; >> + >> =A0 if (record_debug) >> =A0 =A0 fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n"= ); >> >> =A0 record_list_release (record_list); >> + >> + =A0/* Release record_core_regbuf. =A0*/ >> + =A0if (record_core_regbuf) >> + =A0 =A0{ >> + =A0 =A0 =A0xfree (record_core_regbuf); >> + =A0 =A0 =A0record_core_regbuf =3D NULL; >> + =A0 =A0} >> + >> + =A0/* Release record_core_buf_list. =A0*/ >> + =A0if (record_core_buf_list) >> + =A0 =A0{ >> + =A0 =A0 =A0for (entry =3D record_core_buf_list->prev; entry; entry =3D >> entry->prev) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0xfree (record_core_buf_list); >> + =A0 =A0 =A0 =A0 =A0record_core_buf_list =3D entry; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0record_core_buf_list =3D NULL; >> + =A0 =A0} >> =A0} >> >> =A0static int record_resume_step =3D 0; >> @@ -584,7 +938,7 @@ record_wait (struct target_ops *ops, >> =A0 =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 =A0record_resume_step); >> >> - =A0if (!RECORD_IS_REPLAY) >> + =A0if (!RECORD_IS_REPLAY && ops !=3D &record_core_ops) >> =A0 =A0 { >> =A0 =A0 =A0 if (record_resume_error) >> =A0 =A0 =A0 =A0{ >> @@ -712,76 +1066,9 @@ record_wait (struct target_ops *ops, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> =A0 =A0 =A0 =A0 =A0 =A0} >> >> - =A0 =A0 =A0 =A0 /* Set ptid, register and memory according to record_l= ist. =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 "P= rocess record: record_reg %s to " >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "i= nferior num =3D %d.\n", >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ho= st_address_to_string (record_list), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 re= cord_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_REGIS= TER_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 /* Nothing to do if the entry is flagged not_a= ccessible. =A0*/ >> - =A0 =A0 =A0 =A0 =A0 =A0 if (!record_list->u.mem.mem_entry_not_accessib= le) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gdb_byte *mem =3D alloca (record_list-= >u.mem.len); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug > 1) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 "Process record: record_mem %s to >> " >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 "inferior addr =3D %s len =3D %d.\n", >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 host_address_to_string >> (record_list), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 paddress (gdbarch, >> - >> record_list->u.mem.addr), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 record_list->u.mem.len); >> + =A0 =A0 =A0 =A0 =A0record_exec_entry (regcache, gdbarch, record_list); >> >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (target_read_memory (record_list->u= .mem.addr, mem, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 record_list->u.mem.len)) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (execution_direction !=3D E= XEC_REVERSE) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process record: = error reading memory at >> " >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"addr = =3D %s len =3D %d."), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0paddress (g= dbarch, >> record_list->u.mem.addr), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_list= ->u.mem.len); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Read failed -- >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flag entry as not_a= ccessible. =A0*/ >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_list->u.mem.mem_ent= ry_not_accessible =3D 1; >> - =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 if (target_write_memory (recor= d_list->u.mem.addr, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.val, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0record_list->u.mem.len)) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (execution_directio= n !=3D EXEC_REVERSE) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 error (_("Process = record: error writing memory >> at " >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0"addr =3D %s len =3D %d."), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pad= dress (gdbarch, >> record_list->u.mem.addr), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rec= ord_list->u.mem.len); >> - =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 /* Write failed -- >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flag entry = as not_accessible. =A0*/ >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_list->u.mem= .mem_entry_not_accessible =3D >> 1; >> - =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 =A0 =A0 =A0 =A0 memcpy (record_list->u= .mem.val, mem, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record= _list->u.mem.len); >> - =A0 =A0 =A0 =A0 =A0 =A0 =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 =A0 =A0 else >> + =A0 =A0 =A0 =A0 if (record_list->type =3D=3D record_end) >> =A0 =A0 =A0 =A0 =A0 =A0{ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug > 1) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, >> @@ -901,6 +1188,7 @@ record_kill (struct target_ops *ops) >> =A0 =A0 fprintf_unfiltered (gdb_stdlog, "Process record: record_kill\n"); >> >> =A0 unpush_target (&record_ops); >> + >> =A0 target_kill (); >> =A0} >> >> @@ -945,7 +1233,7 @@ record_registers_change (struct regcache >> =A0 record_list =3D record_arch_list_tail; >> >> =A0 if (record_insn_num =3D=3D record_insn_max_num && record_insn_max_nu= m) >> - =A0 =A0record_list_release_first (); >> + =A0 =A0record_list_release_first_insn (); >> =A0 else >> =A0 =A0 record_insn_num++; >> =A0} >> @@ -1058,7 +1346,7 @@ record_xfer_partial (struct target_ops * >> =A0 =A0 =A0 record_list =3D record_arch_list_tail; >> >> =A0 =A0 =A0 if (record_insn_num =3D=3D record_insn_max_num && record_ins= n_max_num) >> - =A0 =A0 =A0 record_list_release_first (); >> + =A0 =A0 =A0 record_list_release_first_insn (); >> =A0 =A0 =A0 else >> =A0 =A0 =A0 =A0record_insn_num++; >> =A0 =A0 } >> @@ -1138,6 +1426,191 @@ init_record_ops (void) >> =A0} >> >> =A0static void >> +record_core_resume (struct target_ops *ops, ptid_t ptid, int step, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enum target_signal siggnal) >> +{ >> + =A0record_resume_step =3D step; >> + =A0record_resume_siggnal =3D siggnal; >> +} >> + >> +static void >> +record_core_kill (struct target_ops *ops) >> +{ >> + =A0if (record_debug) >> + =A0 =A0fprintf_unfiltered (gdb_stdlog, "Process record: >> record_core_kill\n"); >> + >> + =A0unpush_target (&record_core_ops); >> +} >> + >> +static void >> +record_core_fetch_registers (struct target_ops *ops, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct regcach= e *regcache, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int regno) >> +{ >> + =A0if (regno < 0) >> + =A0 =A0{ >> + =A0 =A0 =A0int num =3D gdbarch_num_regs (get_regcache_arch (regcache)); >> + =A0 =A0 =A0int i; >> + >> + =A0 =A0 =A0for (i =3D 0; i < num; i ++) >> + =A0 =A0 =A0 =A0regcache_raw_supply (regcache, i, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_core_re= gbuf + MAX_REGISTER_SIZE * i); >> + =A0 =A0} >> + =A0else >> + =A0 =A0regcache_raw_supply (regcache, regno, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_core_regbuf + M= AX_REGISTER_SIZE * regno); >> +} >> + >> +static void >> +record_core_prepare_to_store (struct regcache *regcache) >> +{ >> +} >> + >> +static void >> +record_core_store_registers (struct target_ops *ops, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct regcach= e *regcache, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int regno) >> +{ >> + =A0if (record_gdb_operation_disable) >> + =A0 =A0regcache_raw_collect (regcache, regno, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_core_regbuf = + MAX_REGISTER_SIZE * >> regno); >> + =A0else >> + =A0 =A0error (_("You can't do that without a process to debug.")); >> +} >> + >> +static LONGEST >> +record_core_xfer_partial (struct target_ops *ops, enum target_object >> object, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const char *annex, gdb= _byte *readbuf, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 const gdb_byte *writeb= uf, ULONGEST offset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0LONGEST len) >> +{ >> + =A0 if (object =3D=3D TARGET_OBJECT_MEMORY) >> + =A0 =A0 { >> + =A0 =A0 =A0 if (record_gdb_operation_disable || !writebuf) >> + =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 struct target_section *p; >> + =A0 =A0 =A0 =A0 =A0 for (p =3D record_core_start; p < record_core_end;= p++) >> + =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (offset >=3D p->addr) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct record_core_buf_entry *entr= y; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (offset >=3D p->endaddr) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (offset + len > p->endaddr) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 len =3D p->endaddr - offset; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 offset -=3D p->addr; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Read readbuf or write writebuf = p, offset, len. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Check flags. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (p->the_bfd_section->flags & SE= C_CONSTRUCTOR >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 || (p->the_bfd_section->fl= ags & SEC_HAS_CONTENTS) >> =3D=3D 0) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (readbuf) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memset (readbuf, 0, le= n); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return len; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Get record_core_buf_entry. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (entry =3D record_core_buf_lis= t; entry; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0entry =3D entry->prev) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (entry->p =3D=3D p) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (writebuf) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!entry) >> + =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 /* Add a new entry= . =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 entry >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D (struct re= cord_core_buf_entry *) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 xmalloc >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (s= izeof (struct >> record_core_buf_entry)); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 entry->p =3D p; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!bfd_malloc_an= d_get_section (p->bfd, >> + >> =A0p->the_bfd_section, >> + =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 =A0 =A0&entry->buf)) >> + =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 =A0 xfree (ent= ry); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 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 =A0 =A0 entry->prev =3D re= cord_core_buf_list; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_core_buf_li= st =3D entry; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memcpy (entry->buf + of= fset, writebuf, (size_t) >> len); >> + =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 =A0 =A0 if (!entry) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return record_beneath_= to_xfer_partial >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(re= cord_beneath_to_xfer_partial_ops, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ob= ject, annex, readbuf, writebuf, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 of= fset, len); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy (readbuf, entry->bu= f + offset, (size_t) >> len); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return len; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 =A0 } >> + >> + =A0 =A0 =A0 =A0 =A0 return -1; >> + =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 else >> + =A0 =A0 =A0 =A0 error (_("You can't do that without a process to debug= .")); >> + =A0 =A0 } >> + >> + =A0return record_beneath_to_xfer_partial >> (record_beneath_to_xfer_partial_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); >> +} >> + >> +static int >> +record_core_insert_breakpoint (struct gdbarch *gdbarch, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct bp_t= arget_info *bp_tgt) >> +{ >> + =A0return 0; >> +} >> + >> +static int >> +record_core_remove_breakpoint (struct gdbarch *gdbarch, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct bp_t= arget_info *bp_tgt) >> +{ >> + =A0return 0; >> +} >> + >> +int >> +record_core_has_execution (struct target_ops *ops) >> +{ >> + =A0return 1; >> +} >> + >> +static void >> +init_record_core_ops (void) >> +{ >> + =A0record_core_ops.to_shortname =3D "record_core"; >> + =A0record_core_ops.to_longname =3D "Process record and replay target"; >> + =A0record_core_ops.to_doc =3D >> + =A0 =A0"Log program while executing and replay execution from log."; >> + =A0record_core_ops.to_open =3D record_open; >> + =A0record_core_ops.to_close =3D record_close; >> + =A0record_core_ops.to_resume =3D record_core_resume; >> + =A0record_core_ops.to_wait =3D record_wait; >> + =A0record_core_ops.to_kill =3D record_core_kill; >> + =A0record_core_ops.to_fetch_registers =3D record_core_fetch_registers; >> + =A0record_core_ops.to_prepare_to_store =3D record_core_prepare_to_stor= e; >> + =A0record_core_ops.to_store_registers =3D record_core_store_registers; >> + =A0record_core_ops.to_xfer_partial =3D record_core_xfer_partial; >> + =A0record_core_ops.to_insert_breakpoint =3D record_core_insert_breakpo= int; >> + =A0record_core_ops.to_remove_breakpoint =3D record_core_remove_breakpo= int; >> + =A0record_core_ops.to_can_execute_reverse =3D record_can_execute_rever= se; >> + =A0record_core_ops.to_has_execution =3D record_core_has_execution; >> + =A0record_core_ops.to_stratum =3D record_stratum; >> + =A0record_core_ops.to_magic =3D OPS_MAGIC; >> +} >> + >> +static void >> =A0show_record_debug (struct ui_file *file, int from_tty, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct cmd_list_element *c, const ch= ar *value) >> =A0{ >> @@ -1153,6 +1626,212 @@ cmd_record_start (char *args, int from_t >> =A0 execute_command ("target record", from_tty); >> =A0} >> >> +static void >> +cmd_record_load (char *args, int from_tty) >> +{ >> + =A0char buf[512]; >> + >> + =A0snprintf (buf, 512, "target record %s", args); >> + =A0execute_command (buf, from_tty); >> +} >> + >> +static inline void >> +record_write_dump (char *recfilename, int fildes, const void *buf, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 size_t nbyte) >> +{ >> + =A0if (write (fildes, buf, nbyte) !=3D nbyte) >> + =A0 =A0error (_("Failed to write dump of execution records to '%s'."), >> + =A0 =A0 =A0 =A0 =A0 recfilename); >> +} >> + >> +/* Record log save-file format >> + =A0 Version 1 >> + >> + =A0 Header: >> + =A0 =A0 4 bytes: magic number htonl(0x20090726). >> + =A0 =A0 =A0 NOTE: be sure to change whenever this file format changes! >> + >> + =A0 Records: >> + =A0 =A0 record_end: >> + =A0 =A0 =A0 1 byte: =A0record type (record_end). >> + =A0 =A0 record_reg: >> + =A0 =A0 =A0 1 byte: =A0record type (record_reg). >> + =A0 =A0 =A0 8 bytes: register id (network byte order). >> + =A0 =A0 =A0 MAX_REGISTER_SIZE bytes: register value. >> + =A0 =A0 record_mem: >> + =A0 =A0 =A0 1 byte: =A0record type (record_mem). >> + =A0 =A0 =A0 8 bytes: memory address (network byte order). >> + =A0 =A0 =A0 8 bytes: memory length (network byte order). >> + =A0 =A0 =A0 n bytes: memory value (n =3D=3D memory length). >> +*/ >> + >> +/* Dump the execution log to a file. =A0*/ >> + >> +static void >> +cmd_record_dump (char *args, int from_tty) >> +{ >> + =A0char *recfilename, recfilename_buffer[40]; >> + =A0int recfd; >> + =A0struct record_entry *cur_record_list; >> + =A0uint32_t magic; >> + =A0struct regcache *regcache; >> + =A0struct gdbarch *gdbarch; >> + =A0struct cleanup *old_cleanups; >> + =A0struct cleanup *set_cleanups; >> + >> + =A0if (strcmp (current_target.to_shortname, "record") !=3D 0) >> + =A0 =A0error (_("Process record is not started.\n")); >> + >> + =A0if (args && *args) >> + =A0 =A0recfilename =3D args; >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0/* Default corefile name is "gdb_record.PID". =A0*/ >> + =A0 =A0 =A0snprintf (recfilename_buffer, 40, "gdb_record.%d", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0PIDGET (inferior_ptid)); >> + =A0 =A0 =A0recfilename =3D recfilename_buffer; >> + =A0 =A0} >> + >> + =A0/* Open the dump file. =A0*/ >> + =A0if (record_debug) >> + =A0 =A0fprintf_unfiltered (gdb_stdlog, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Saving recording to = file '%s'\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename); >> + =A0recfd =3D open (recfilename, O_WRONLY | O_CREAT | O_TRUNC | O_BINAR= Y, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0S_IRUSR | S_IWUSR); >> + =A0if (recfd < 0) >> + =A0 =A0error (_("Failed to open '%s' for dump execution records: %s"), >> + =A0 =A0 =A0 =A0 =A0 recfilename, strerror (errno)); >> + =A0old_cleanups =3D make_cleanup (record_fd_cleanups, &recfd); >> + >> + =A0/* Save the current record entry to "cur_record_list". =A0*/ >> + =A0cur_record_list =3D record_list; >> + >> + =A0/* Get the values of regcache and gdbarch. =A0*/ >> + =A0regcache =3D get_current_regcache (); >> + =A0gdbarch =3D get_regcache_arch (regcache); >> + >> + =A0/* Disable the GDB operation record. =A0*/ >> + =A0set_cleanups =3D record_gdb_operation_disable_set (); >> + >> + =A0/* Write the magic code. =A0*/ >> + =A0magic =3D RECORD_FILE_MAGIC; >> + =A0if (record_debug) >> + =A0 =A0fprintf_unfiltered (gdb_stdlog, _("\ >> +Writing 4-byte magic cookie RECORD_FILE_MAGIC (0x%08x)\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0magic); >> + =A0record_write_dump (recfilename, recfd, &magic, 4); >> + >> + =A0/* Reverse execute to the begin of record list. =A0*/ >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0/* Check for beginning and end of log. =A0*/ >> + =A0 =A0 =A0if (record_list =3D=3D &record_first) >> + =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0record_exec_entry (regcache, gdbarch, record_list); >> + >> + =A0 =A0 =A0if (record_list->prev) >> + =A0 =A0 =A0 =A0record_list =3D record_list->prev; >> + =A0 =A0} >> + >> + =A0/* Dump the entries to recfd and forward execute to the end of >> + =A0 =A0 record list. =A0*/ >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0/* Dump entry. =A0*/ >> + =A0 =A0 =A0if (record_list !=3D &record_first) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0uint8_t tmpu8; >> + =A0 =A0 =A0 =A0 =A0uint64_t tmpu64; >> + >> + =A0 =A0 =A0 =A0 =A0tmpu8 =3D record_list->type; >> + =A0 =A0 =A0 =A0 =A0record_write_dump (recfilename, recfd, &tmpu8, 1); >> + >> + =A0 =A0 =A0 =A0 =A0switch (record_list->type) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0case record_reg: /* reg */ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, _("\ >> +Writing register %d (1 plus 8 plus %d bytes)\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0record_list->u.reg.num, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0MAX_REGISTER_SIZE); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D record_list->u.reg.num; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D bswap_64 (tmpu64); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_write_dump (recfilename, recfd, &tmp= u64, 8); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_write_dump (recfilename, recfd, >> record_list->u.reg.val, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MAX_RE= GISTER_SIZE); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0case record_mem: /* mem */ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!record_list->u.mem.mem_entry_not_acces= sible) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog,= _("\ >> +Writing memory %s (1 plus 8 plus 8 bytes plus %d bytes)\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0paddress (gdbarch, >> + >> =A0record_list->u.mem.addr), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0record_list->u.mem.len); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D record_list->u.mem.addr; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D bswap_64 (tmpu64); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_write_dump (recfilename, rec= fd, &tmpu64, 8); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D record_list->u.mem.len; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tmpu64 =3D bswap_64 (tmpu64); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_write_dump (recfilename, rec= fd, &tmpu64, 8); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_write_dump (recfilename, rec= fd, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 record_list->u.mem.val, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 record_list->u.mem.len); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0case record_end: >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* FIXME: record the contents of record= _end rec. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0_("Writing record_end (1 >> byte)\n")); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0/* Execute entry. =A0*/ >> + =A0 =A0 =A0record_exec_entry (regcache, gdbarch, record_list); >> + >> + =A0 =A0 =A0if (record_list->next) >> + =A0 =A0 =A0 =A0record_list =3D record_list->next; >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0break; >> + =A0 =A0} >> + >> + =A0/* Reverse execute to cur_record_list. =A0*/ >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0/* Check for beginning and end of log. =A0*/ >> + =A0 =A0 =A0if (record_list =3D=3D cur_record_list) >> + =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0record_exec_entry (regcache, gdbarch, record_list); >> + >> + =A0 =A0 =A0if (record_list->prev) >> + =A0 =A0 =A0 =A0record_list =3D record_list->prev; >> + =A0 =A0} >> + >> + =A0do_cleanups (set_cleanups); >> + =A0do_cleanups (old_cleanups); >> + >> + =A0/* Succeeded. =A0*/ >> + =A0fprintf_filtered (gdb_stdout, _("Saved dump of execution " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"re= cords to `%s'.\n"), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0recfilename); >> +} >> + >> =A0/* Truncate the record log from the present point >> =A0 =A0of replay until the end. =A0*/ >> >> @@ -1185,7 +1864,12 @@ cmd_record_stop (char *args, int from_tt >> =A0 =A0 { >> =A0 =A0 =A0 if (!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 =A0"stop recording?"))) >> - =A0 =A0 =A0 unpush_target (&record_ops); >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0if (strcmp (current_target.to_shortname, "record") = =3D=3D 0) >> + =A0 =A0 =A0 =A0 =A0 unpush_target (&record_ops); >> + =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0unpush_target (&record_core_ops); >> + =A0 =A0 =A0 =A0} >> =A0 =A0 } >> =A0 else >> =A0 =A0 printf_unfiltered (_("Process record is not started.\n")); >> @@ -1203,7 +1887,7 @@ set_record_insn_max_num (char *args, int >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "the first ones?\n")= ); >> >> =A0 =A0 =A0 while (record_insn_num > record_insn_max_num) >> - =A0 =A0 =A0 record_list_release_first (); >> + =A0 =A0 =A0 record_list_release_first_insn (); >> =A0 =A0 } >> =A0} >> >> @@ -1243,6 +1927,8 @@ info_record_command (char *args, int fro >> =A0void >> =A0_initialize_record (void) >> =A0{ >> + =A0struct cmd_list_element *c; >> + >> =A0 /* Init record_first. =A0*/ >> =A0 record_first.prev =3D NULL; >> =A0 record_first.next =3D NULL; >> @@ -1250,6 +1936,8 @@ _initialize_record (void) >> >> =A0 init_record_ops (); >> =A0 add_target (&record_ops); >> + =A0init_record_core_ops (); >> + =A0add_target (&record_core_ops); >> >> =A0 add_setshow_zinteger_cmd ("record", no_class, &record_debug, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Set debugging = of record/replay feature."), >> @@ -1259,9 +1947,10 @@ _initialize_record (void) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NULL, show_record= _debug, &setdebuglist, >> =A0 =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, &cmdlis= t); >> + =A0c =3D add_prefix_cmd ("record", class_obscure, cmd_record_start, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 _("Abbreviated form of \"targe= t record\" command."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist, "record ", 0,= &cmdlist); >> + =A0set_cmd_completer (c, filename_completer); >> =A0 add_com_alias ("rec", "record", class_obscure, 1); >> =A0 add_prefix_cmd ("record", class_support, set_record_command, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Set record options"), &set_record_= cmdlist, >> @@ -1276,6 +1965,16 @@ _initialize_record (void) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"info record ", 0, &infolist); >> =A0 add_alias_cmd ("rec", "record", class_obscure, 1, &infolist); >> >> + =A0c =3D add_cmd ("load", class_obscure, cmd_record_load, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Load previously dumped execution records= from \ >> +a file given as argument."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist); >> + =A0set_cmd_completer (c, filename_completer); >> + =A0c =3D add_cmd ("dump", class_obscure, cmd_record_dump, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0_("Dump the execution records to a file.\n\ >> +Argument is optional filename. =A0Default filename is >> 'gdb_record.'."), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 &record_cmdlist); >> + =A0set_cmd_completer (c, filename_completer); >> >> =A0 add_cmd ("delete", class_obscure, cmd_record_delete, >> =A0 =A0 =A0 =A0 =A0 _("Delete the rest of execution log and start record= ing it >> anew."), > >