From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9552 invoked by alias); 26 Nov 2009 07:36:46 -0000 Received: (qmail 9512 invoked by uid 22791); 26 Nov 2009 07:36: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-px0-f175.google.com (HELO mail-px0-f175.google.com) (209.85.216.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 26 Nov 2009 07:36:33 +0000 Received: by pxi5 with SMTP id 5so361954pxi.12 for ; Wed, 25 Nov 2009 23:36:32 -0800 (PST) MIME-Version: 1.0 Received: by 10.143.21.30 with SMTP id y30mr976442wfi.229.1259220992084; Wed, 25 Nov 2009 23:36:32 -0800 (PST) In-Reply-To: <4B0D8714.4080500@vmware.com> References: <4B0D8714.4080500@vmware.com> From: Hui Zhu Date: Thu, 26 Nov 2009 07:36:00 -0000 Message-ID: Subject: Re: [RFA/RFC] Prec multi-thread support [4/4] record target To: Michael Snyder Cc: gdb-patches ml 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-11/txt/msg00569.txt.bz2 Sorry for I forget it. To use this patch need patch http://sourceware.org/ml/gdb-patches/2009-11/msg00520.html first. prec-fix-error-handler.txt is still in discussion. But looks we are moving= on. If we don't finish prec-fix-error-handler.txt in one or two days, I will post a new prec-thread-target.txt for cvs head. BTW, even if new prec-fix-error-handler.txt check in, I still need post a new prec-thread-target.txt too. :P Thanks, Hui On Thu, Nov 26, 2009 at 03:35, Michael Snyder wrote: > Hi Hui, > > This one (4 of 4) does not seem to apply cleanly against cvs head > (record.c is cvs revision 1.40). > > Since the rejected diffs seem to have to do with do_record_message, > I'm guessing that you may have experienced some "bleed" between this > patch and another one that you're working on. > > Can you sort it out? =A0This patch should only include thread > support, not fixes for the do_record_message issue. > > Thanks, > Michael > > > Hui Zhu wrote: >> >> To record the multithread inferior, record let each thread exec one by >> one. For example: >> Inferior have 2 threads t1 and t2. >> 1. set t1 to inferior_ptid. >> 2. record_message t1. >> 3. resume t1. >> 4. wait t1. >> 5. Check if t1 get breakpoint or someting. =A0If so, return. >> 5. set t2 to inferior_ptid. >> 6. record_message t2. >> 7. resume t2. >> 8. wait t2. >> 9. Check if t2 get breakpoint or someting. =A0If so, return. >> 10. Check if step, if so return. =A0If not, goto 1. >> >> But there is a problem that thread will hang by a lock sometime. =A0If >> t1 is waiting a lock and t2 have it. =A0GDB and inferior will dead lock >> in there. >> So record call wait with TARGET_WNOHANG. After we get >> TARGET_WAITKIND_IGNORE (thread is keep running), we will set >> tp->record_is_waiting to 1 that flag thread is running. >> And record set non_stop to 1, because if we want linux-nat handle 2 >> thread running. =A0This is the only way. =A0If not set, GDB will get a l= ot >> of internal_error. >> Then the inferior exec will be: >> 1. set t1 to inferior_ptid. >> 2. If t1->record_is_waiting is 0, record_message t1. >> 3. If t1->record_is_waiting is 0, resume t1. >> 4. wait t1. >> 5. If get TARGET_WAITKIND_IGNORE, set t1->record_is_waiting to 1. >> Check if t1 get breakpoint or someting. =A0If so, return. >> 5. set t2 to inferior_ptid. >> 6. If t2->record_is_waiting is 0, record_message t2. >> 7. If t2->record_is_waiting is 0, resume t2. >> 8. wait t2. >> 9. If get TARGET_WAITKIND_IGNORE, set t2->record_is_waiting to 1. >> Check if t2 get breakpoint or someting. =A0If so, return. >> 10. Check if step, if so return. =A0If not, goto 1. >> >> Before record_wait return, it will call iterate_over_threads >> (record_thread_stop_callback, NULL) to stop each thread that >> record_is_waiting is 1. >> >> >> And if this is a single thread or just one thread exec, record will >> exec it like before. >> record_new_thread_observer and record_thread_exit_observer make record >> know how much thread in inferior. >> >> >> 2009-11-25 =A0Hui Zhu =A0 >> >> =A0 =A0 =A0 =A0* record.c (observer.h): New include. >> =A0 =A0 =A0 =A0(RECORD_THREAD): New macro. >> =A0 =A0 =A0 =A0(record_type): Add record_ptid. >> =A0 =A0 =A0 =A0(record_entry): Add ptid. >> =A0 =A0 =A0 =A0(record_prev_ptid, >> =A0 =A0 =A0 =A0record_new_thread_observer, >> =A0 =A0 =A0 =A0record_thread_exit_observer): New variable. >> =A0 =A0 =A0 =A0(record_ptid_alloc, record_ptid_release): New function. >> =A0 =A0 =A0 =A0(record_entry_release): Add record_ptid. >> =A0 =A0 =A0 =A0(record_entry_remove_from_list, >> =A0 =A0 =A0 =A0record_arch_list_add_ptid): New function. >> =A0 =A0 =A0 =A0(record_message_args): Remove regcache. >> =A0 =A0 =A0 =A0(record_message): Add code for multithread. >> =A0 =A0 =A0 =A0(do_record_message): Remove regcache. >> =A0 =A0 =A0 =A0(record_exec_insn): Remove regcache, gdbarch. =A0Add >> =A0 =A0 =A0 =A0regcache_p, gdbarch_p, aspace_p. >> =A0 =A0 =A0 =A0Add suport for record_ptid. >> =A0 =A0 =A0 =A0(record_thread_number): New variable. >> =A0 =A0 =A0 =A0(record_thread_number_count, >> =A0 =A0 =A0 =A0record_thread_number_reset, >> =A0 =A0 =A0 =A0record_new_thread_handler, >> =A0 =A0 =A0 =A0record_thread_exit_handler): New function. >> =A0 =A0 =A0 =A0(record_open_1): Add record_new_thread_observer >> =A0 =A0 =A0 =A0and record_thread_exit_observer. >> =A0 =A0 =A0 =A0(record_open): Add record_prev_ptid >> =A0 =A0 =A0 =A0and record_thread_number_reset. >> =A0 =A0 =A0 =A0(record_close): Add record_new_thread_observer >> =A0 =A0 =A0 =A0and record_thread_exit_observer. >> =A0 =A0 =A0 =A0(record_resume_ptid, record_resume_signal): New variable. >> =A0 =A0 =A0 =A0(record_resume): Add code for multithread. >> =A0 =A0 =A0 =A0(record_thread_wait_args): New struct. >> =A0 =A0 =A0 =A0(record_thread_reset_callback, >> =A0 =A0 =A0 =A0record_thread_stop_callback, >> =A0 =A0 =A0 =A0record_thread_wait, >> =A0 =A0 =A0 =A0record_thread_wait_callback, >> =A0 =A0 =A0 =A0record_wait_signal_cleanups) New function. >> =A0 =A0 =A0 =A0(record_wait_cleanups): Change to record_wait_replay_clea= nups. >> =A0 =A0 =A0 =A0(record_wait_mthread_cleanups): New function. >> =A0 =A0 =A0 =A0(record_wait): Add code for multithread. >> =A0 =A0 =A0 =A0(record_registers_change): Ditto. >> =A0 =A0 =A0 =A0(record_xfer_partial): Ditto. >> =A0 =A0 =A0 =A0(record_restore): Add code restore record_ptid entry. >> =A0 =A0 =A0 =A0(cmd_record_save): Add code save record_ptid entry. >> =A0 =A0 =A0 =A0(record_goto_insn): Update argument to call record_exec_i= nsn. >> =A0 =A0 =A0 =A0record.h (record_step): New extern. >> >> --- >> =A0record.c | =A0734 >> ++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- >> =A0record.h | =A0 =A01 >> =A02 files changed, 631 insertions(+), 104 deletions(-) >> >> --- a/record.c >> +++ b/record.c >> @@ -30,6 +30,7 @@ >> =A0#include "record.h" >> =A0#include "elf-bfd.h" >> =A0#include "gcore.h" >> +#include "observer.h" >> >> =A0#include >> >> @@ -60,6 +61,8 @@ >> >> =A0#define RECORD_FILE_MAGIC =A0 =A0 =A0netorder32(0x20091016) >> >> +#define RECORD_THREAD =A0(current_target.beneath->beneath->to_stratum = =3D=3D >> thread_stratum) >> + >> =A0/* These are the core structs of the process record functionality. >> >> =A0 =A0A record_entry is a record of the value change of a register >> @@ -106,7 +109,8 @@ enum record_type >> =A0{ >> =A0 record_end =3D 0, >> =A0 record_reg, >> - =A0record_mem >> + =A0record_mem, >> + =A0record_ptid >> =A0}; >> >> =A0/* This is the data structure that makes up the execution log. >> @@ -144,6 +148,8 @@ struct record_entry >> =A0 =A0 struct record_reg_entry reg; >> =A0 =A0 /* mem */ >> =A0 =A0 struct record_mem_entry mem; >> + =A0 =A0/* ptid */ >> + =A0 =A0ptid_t ptid; >> =A0 =A0 /* end */ >> =A0 =A0 struct record_end_entry end; >> =A0 } u; >> @@ -196,10 +202,19 @@ static int record_insn_num =3D 0; >> =A0 =A0than count of insns presently in execution log). =A0*/ >> =A0static ULONGEST record_insn_count; >> >> +/* In record mode, it's the step of next resume. =A0*/ >> +int record_step; >> + >> +/* The current inferior_ptid that is recorded. =A0*/ >> +static ptid_t record_prev_ptid; >> + >> =A0/* The target_ops of process record. =A0*/ >> =A0static struct target_ops record_ops; >> =A0static struct target_ops record_core_ops; >> >> +static struct observer *record_new_thread_observer =3D NULL; >> +static struct observer *record_thread_exit_observer =3D NULL; >> + >> =A0/* The beneath function pointers. =A0*/ >> =A0static struct target_ops *record_beneath_to_resume_ops; >> =A0static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, >> int, >> @@ -288,6 +303,27 @@ record_mem_release (struct record_entry >> =A0 xfree (rec); >> =A0} >> >> +/* Alloc a record_ptid record entry. =A0*/ >> + >> +static inline struct record_entry * >> +record_ptid_alloc (void) >> +{ >> + =A0struct record_entry *rec; >> + >> + =A0rec =3D (struct record_entry *) xcalloc (1, sizeof (struct >> record_entry)); >> + =A0rec->type =3D record_ptid; >> + >> + =A0return rec; >> +} >> + >> +/* Free a record_ptid record entry. =A0*/ >> + >> +static inline void >> +record_ptid_release (struct record_entry *rec) >> +{ >> + =A0xfree (rec); >> +} >> + >> =A0/* Alloc a record_end record entry. =A0*/ >> >> =A0static inline struct record_entry * >> @@ -324,6 +360,9 @@ record_entry_release (struct record_entr >> =A0 case record_mem: >> =A0 =A0 record_mem_release (rec); >> =A0 =A0 break; >> + =A0case record_ptid: >> + =A0 =A0record_ptid_release (rec); >> + =A0 =A0break; >> =A0 case record_end: >> =A0 =A0 record_end_release (rec); >> =A0 =A0 break; >> @@ -331,6 +370,16 @@ record_entry_release (struct record_entr >> =A0 return type; >> =A0} >> >> +/* Remove one record entry from record_list. =A0*/ >> + >> +static void >> +record_entry_remove_from_list (struct record_entry *rec) >> +{ >> + =A0if (rec->next) >> + =A0 =A0rec->next->prev =3D rec->prev; >> + =A0rec->prev->next =3D rec->next; >> +} >> + >> =A0/* Free all record entries in list pointed to by REC. =A0*/ >> >> =A0static void >> @@ -512,6 +561,24 @@ record_arch_list_add_mem (CORE_ADDR addr >> =A0 return 0; >> =A0} >> >> +static void >> +record_arch_list_add_ptid (ptid_t *ptid) >> +{ >> + =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 ptid = =3D %s 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 target_pid_to_str (*ptid)); >> + >> + =A0rec =3D record_ptid_alloc (); >> + >> + =A0rec->u.ptid =3D *ptid; >> + >> + =A0record_arch_list_add (rec); >> +} >> + >> =A0/* Add a record_end type struct record_entry to record_arch_list. =A0= */ >> >> =A0int >> @@ -573,7 +640,6 @@ record_arch_list_cleanups (void *ignore) >> =A0 =A0record_arch_list, and add it to record_list. =A0*/ >> >> =A0struct record_message_args { >> - =A0struct regcache *regcache; >> =A0 enum target_signal signal; >> =A0}; >> >> @@ -582,15 +648,21 @@ record_message (void *args) >> =A0{ >> =A0 int ret; >> =A0 struct record_message_args *myargs =3D args; >> - =A0struct gdbarch *gdbarch =3D get_regcache_arch (myargs->regcache); >> + =A0struct regcache *regcache; >> + =A0struct gdbarch *gdbarch; >> =A0 struct cleanup *old_cleanups =3D make_cleanup (record_arch_list_clea= nups, >> 0); >> >> + =A0record_step =3D 1; >> + >> =A0 record_arch_list_head =3D NULL; >> =A0 record_arch_list_tail =3D NULL; >> >> =A0 /* Check record_insn_num. =A0*/ >> =A0 record_check_insn_num (1); >> >> + =A0regcache =3D get_current_regcache (); >> + =A0gdbarch =3D get_regcache_arch (regcache); >> + >> =A0 /* If gdb sends a signal value to target_resume, >> =A0 =A0 =A0save it in the 'end' field of the previous instruction. >> >> @@ -613,20 +685,45 @@ record_message (void *args) >> =A0 =A0 =A0But we should still deliver the signal to gdb during the repl= ay, >> =A0 =A0 =A0if we delivered it during the recording. =A0Therefore we shou= ld >> =A0 =A0 =A0record the signal during record_wait, not record_resume. =A0*/ >> - =A0if (record_list !=3D &record_first) =A0 =A0/* FIXME better way to c= heck */ >> + =A0if (ptid_equal (record_prev_ptid, inferior_ptid)) >> =A0 =A0 { >> - =A0 =A0 =A0gdb_assert (record_list->type =3D=3D record_end); >> - =A0 =A0 =A0record_list->u.end.sigval =3D myargs->signal; >> + =A0 =A0 =A0if (myargs->signal !=3D TARGET_SIGNAL_0) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0gdb_assert (record_list->type =3D=3D record_end); >> + =A0 =A0 =A0 =A0 =A0record_list->u.end.sigval =3D myargs->signal; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0if (myargs->signal !=3D TARGET_SIGNAL_0) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0struct record_entry *rec; >> + =A0 =A0 =A0 =A0 =A0for (rec =3D record_list; rec !=3D record_first.nex= t; rec =3D >> rec->prev) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (rec->type =3D=3D record_ptid >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&& ptid_equal (rec->u.ptid, inferio= r_ptid)) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gdb_assert (rec->prev->type =3D=3D = record_end); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rec->prev->u.end.sigval =3D myargs-= >signal; >> + =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/* If the inferior_ptid change (inferior_ptid is not same w= ith >> + =A0 =A0 =A0 =A0 record_prev_ptid), record record_prev_ptid to record l= ist. =A0*/ >> + =A0 =A0 =A0record_arch_list_add_ptid (&record_prev_ptid); >> + =A0 =A0 =A0record_prev_ptid =3D inferior_ptid; >> =A0 =A0 } >> >> =A0 if (myargs->signal =3D=3D TARGET_SIGNAL_0 >> =A0 =A0 =A0 || !gdbarch_process_record_signal_p (gdbarch)) >> =A0 =A0 ret =3D gdbarch_process_record (gdbarch, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 myargs= ->regcache, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcac= he_read_pc (myargs->regcache)); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcac= he, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcac= he_read_pc (regcache)); >> =A0 else >> =A0 =A0 ret =3D gdbarch_process_record_signal (gdbarch, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0myargs->regcache, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0regcache, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 myargs->signal); >> >> =A0 if (ret > 0) >> @@ -649,12 +746,10 @@ record_message (void *args) >> =A0} >> >> =A0static int >> -do_record_message (struct regcache *regcache, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0enum target_signal signal, int catc= h) >> +do_record_message (enum target_signal signal, int catch) >> =A0{ >> =A0 struct record_message_args args; >> >> - =A0args.regcache =3D regcache; >> =A0 args.signal =3D signal; >> >> =A0 if (catch) >> @@ -688,9 +783,14 @@ static int record_hw_watchpoint =3D 0; >> =A0 =A0entries and memory entries, followed by an 'end' entry. =A0*/ >> >> =A0static inline void >> -record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch, >> +record_exec_insn (struct regcache **regcache_p, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct gdbarch **gdbarch_p, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct address_space **aspace_p, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct record_entry *entry) >> =A0{ >> + =A0struct regcache *regcache =3D *regcache_p; >> + =A0struct gdbarch *gdbarch =3D *gdbarch_p; >> + >> =A0 switch (entry->type) >> =A0 =A0 { >> =A0 =A0 case record_reg: /* reg */ >> @@ -769,6 +869,110 @@ record_exec_insn (struct regcache *regca >> =A0 =A0 =A0 =A0 =A0 } >> =A0 =A0 =A0 } >> =A0 =A0 =A0 break; >> + >> + =A0 =A0case record_ptid: /* ptid */ >> + =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0ptid_t tmp_ptid; >> + >> + =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_ptid %s to " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"inferior p= tid =3D %s.\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 =A0target_pid_= to_str (entry->u.ptid)); >> + >> + =A0 =A0 =A0 =A0if (!ptid_equal (entry->u.ptid, null_ptid)) >> + =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0inferior_ptid =3D entry->u.ptid; >> + =A0 =A0 =A0 =A0 =A0 =A0*regcache_p =3D get_current_regcache (); >> + =A0 =A0 =A0 =A0 =A0 =A0*gdbarch_p =3D get_regcache_arch (*regcache_p); >> + =A0 =A0 =A0 =A0 =A0 =A0*aspace_p =3D get_regcache_aspace (*regcache_p); >> + =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0tmp_ptid =3D entry->u.ptid; >> + =A0 =A0 =A0 =A0entry->u.ptid =3D record_prev_ptid; >> + =A0 =A0 =A0 =A0record_prev_ptid =3D tmp_ptid; >> + =A0 =A0 =A0} >> + =A0 =A0 =A0break; >> + =A0 =A0} >> +} >> + >> +static int record_thread_number; >> + >> +static int >> +record_thread_number_count (struct thread_info *thread, void *unused) >> +{ >> + =A0if (thread->state_ !=3D THREAD_EXITED) >> + =A0 =A0record_thread_number ++; >> + >> + =A0return 0; >> +} >> + >> +static void >> +record_thread_number_reset (void) >> +{ >> + =A0record_thread_number =3D 0; >> + >> + =A0if (RECORD_THREAD) >> + =A0 =A0iterate_over_threads (record_thread_number_count, NULL); >> +} >> + >> +static void >> +record_new_thread_handler (struct thread_info *tp) >> +{ >> + =A0tp->record_is_waiting =3D 0; >> + >> + =A0record_thread_number_reset (); >> +} >> + >> +static void >> +record_thread_exit_handler (struct thread_info *tp, int silent) >> +{ >> + =A0struct record_entry *rec; >> + =A0ptid_t cur_ptid =3D record_prev_ptid; >> + >> + =A0if (!record_first.next) >> + =A0 =A0return; >> + >> + =A0tp->record_is_waiting =3D 0; >> + >> + =A0if (tp->state_ !=3D THREAD_EXITED) >> + =A0 =A0{ >> + =A0 =A0 =A0gdb_assert (record_thread_number > 0); >> + =A0 =A0 =A0record_thread_number --; >> + =A0 =A0} >> + >> + =A0/* Delete all the record_reg and record_ptid for tp->ptid >> + =A0 =A0 from record list. =A0*/ >> + =A0for (rec =3D record_list; rec !=3D &record_first;) >> + =A0 =A0{ >> + =A0 =A0 =A0struct record_entry *tmp =3D rec; >> + =A0 =A0 =A0rec =3D rec->prev; >> + >> + =A0 =A0 =A0switch (tmp->type) { >> + =A0 =A0 =A0 =A0case record_reg: >> + =A0 =A0 =A0 =A0 =A0/* If this record_reg is for tp->ptid, delte it. = =A0*/ >> + =A0 =A0 =A0 =A0 =A0if (ptid_equal (cur_ptid, tp->ptid)) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_entry_remove_from_list (tmp); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_entry_release (tmp); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0case record_ptid: >> + =A0 =A0 =A0 =A0 =A0/* If this record_ptid is for tp->ptid, delte it. = =A0*/ >> + =A0 =A0 =A0 =A0 =A0cur_ptid =3D tmp->u.ptid; >> + =A0 =A0 =A0 =A0 =A0if (ptid_equal (record_prev_ptid, tp->ptid)) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_prev_ptid =3D cur_ptid; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_entry_remove_from_list (tmp); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_entry_release (tmp); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0else if (ptid_equal (cur_ptid, tp->ptid)) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_entry_remove_from_list (tmp); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0record_entry_release (tmp); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0} >> =A0 =A0 } >> =A0} >> >> @@ -865,6 +1069,9 @@ record_open_1 (char *name, int from_tty) >> =A0 =A0 error (_("Could not find 'to_remove_breakpoint' method on the >> target stack.")); >> >> =A0 push_target (&record_ops); >> + >> + =A0record_new_thread_observer =3D observer_attach_new_thread >> (record_new_thread_handler); >> + =A0record_thread_exit_observer =3D observer_attach_thread_exit >> (record_thread_exit_handler); >> =A0} >> >> =A0/* "to_open" target method. =A0Open the process record target. =A0*/ >> @@ -934,6 +1141,7 @@ record_open (char *name, int from_tty) >> =A0 record_insn_count =3D 0; >> =A0 record_list =3D &record_first; >> =A0 record_list->next =3D NULL; >> + =A0record_prev_ptid =3D null_ptid; >> >> =A0 /* Set the tmp beneath pointers to beneath pointers. =A0*/ >> =A0 record_beneath_to_resume_ops =3D tmp_to_resume_ops; >> @@ -953,6 +1161,8 @@ record_open (char *name, int from_tty) >> =A0 =A0 record_core_open_1 (name, from_tty); >> =A0 else >> =A0 =A0 record_open_1 (name, from_tty); >> + >> + =A0record_thread_number_reset (); >> =A0} >> >> =A0/* "to_close" target method. =A0Close the process record target. =A0*/ >> @@ -965,6 +1175,17 @@ record_close (int quitting) >> =A0 if (record_debug) >> =A0 =A0 fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n"= ); >> >> + =A0if (record_new_thread_observer) >> + =A0 =A0{ >> + =A0 =A0 =A0observer_detach_new_thread (record_new_thread_observer); >> + =A0 =A0 =A0record_new_thread_observer =3D NULL; >> + =A0 =A0} >> + =A0if (record_thread_exit_observer) >> + =A0 =A0{ >> + =A0 =A0 =A0observer_detach_thread_exit (record_thread_exit_observer); >> + =A0 =A0 =A0record_thread_exit_observer =3D NULL; >> + =A0 =A0} >> + >> =A0 record_list_release (record_list); >> >> =A0 /* Release record_core_regbuf. =A0*/ >> @@ -987,6 +1208,8 @@ record_close (int quitting) >> =A0} >> >> =A0static int record_resume_step =3D 0; >> +static ptid_t record_resume_ptid; >> +static enum target_signal record_resume_signal =3D TARGET_SIGNAL_0; >> >> =A0/* "to_resume" target method. =A0Resume the process record target. = =A0*/ >> >> @@ -998,10 +1221,201 @@ record_resume (struct target_ops *ops, p >> >> =A0 if (!RECORD_IS_REPLAY) >> =A0 =A0 { >> - =A0 =A0 =A0do_record_message (get_current_regcache (), signal, 0); >> - =A0 =A0 =A0record_beneath_to_resume (record_beneath_to_resume_ops, pti= d, 1, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0signal); >> + =A0 =A0 =A0record_resume_ptid =3D ptid; >> + =A0 =A0 =A0if (record_thread_number > 1 && !ptid_equal (ptid, inferior= _ptid)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0record_resume_signal =3D signal; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0do_record_message (signal, 0); >> + =A0 =A0 =A0 =A0 =A0record_beneath_to_resume (record_beneath_to_resume_= ops, ptid, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0record_step, signal); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +} >> + >> +struct record_thread_wait_args { >> + =A0ptid_t real_inferior_ptid; >> + =A0struct thread_info *real_inferior_tp; >> + =A0struct target_waitstatus real_inferior_status; >> + >> + =A0struct target_waitstatus *status; >> + =A0int options; >> +}; >> + >> +static int >> +record_thread_reset_callback (struct thread_info *tp, void *data) >> +{ >> + =A0tp->record_is_waiting =3D 0; >> + >> + =A0return 0; >> +} >> + >> +static int >> +record_thread_stop_callback (struct thread_info *tp, void *data) >> +{ >> + =A0if (tp->state_ !=3D THREAD_EXITED && tp->record_is_waiting) >> + =A0 =A0target_stop (tp->ptid); >> + >> + =A0return 0; >> +} >> + >> +/* Return 1 if it is not a simple step. >> + =A0 Return 0 if it is a simple step. =A0*/ >> + >> +static int >> +record_thread_wait (ptid_t ptid, struct target_waitstatus *status, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int options, ptid_t *ret_ptid) >> +{ >> + =A0ptid_t wait_ptid =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 =A0 ptid, status, options); >> + >> + =A0if (ret_ptid) >> + =A0 =A0*ret_ptid =3D wait_ptid; >> + >> + =A0if (status->kind =3D=3D TARGET_WAITKIND_IGNORE) >> + =A0 =A0return 0; >> + >> + =A0inferior_ptid =3D wait_ptid; >> + >> + =A0/* Is this a SIGTRAP? =A0*/ >> + =A0if (status->kind =3D=3D TARGET_WAITKIND_STOPPED >> + =A0 =A0 =A0&& status->value.sig =3D=3D TARGET_SIGNAL_TRAP) >> + =A0 =A0{ >> + =A0 =A0 =A0CORE_ADDR tmp_pc; >> + =A0 =A0 =A0struct regcache *regcache; >> + =A0 =A0 =A0struct gdbarch *gdbarch; >> + =A0 =A0 =A0struct address_space *aspace; >> + =A0 =A0 =A0CORE_ADDR decr_pc_after_break; >> + >> + =A0 =A0 =A0/* Yes -- this is likely our single-step finishing, >> + =A0 =A0 =A0 =A0 but check if there's any reason the core would be >> + =A0 =A0 =A0 =A0 interested in the event. =A0*/ >> + >> + =A0 =A0 =A0registers_changed (); >> + =A0 =A0 =A0regcache =3D get_current_regcache (); >> + =A0 =A0 =A0gdbarch =3D get_regcache_arch (regcache); >> + =A0 =A0 =A0tmp_pc =3D regcache_read_pc (regcache); >> + =A0 =A0 =A0aspace =3D get_regcache_aspace (regcache); >> + =A0 =A0 =A0decr_pc_after_break =3D gdbarch_decr_pc_after_break (gdbarc= h); >> + >> + =A0 =A0 =A0/* To check if this is breakpoint need the right pc, if thi= s is not >> + =A0 =A0 =A0 =A0 a single step. =A0So we need adjust tmp_pc to make it = right. =A0*/ >> + =A0 =A0 =A0if (!record_step) >> + =A0 =A0 =A0 =A0tmp_pc -=3D decr_pc_after_break; >> + >> + =A0 =A0 =A0if (target_stopped_by_watchpoint ()) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0/* Always interested in watchpoints. =A0*/ >> + =A0 =A0 =A0 =A0 =A0return 1; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0else if (breakpoint_inserted_here_p (aspace, tmp_pc)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0/* There is a breakpoint here. =A0Let the core hand= le it. =A0*/ >> + =A0 =A0 =A0 =A0 =A0if (record_step >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0&& software_breakpoint_inserted_here_p (asp= ace, tmp_pc)) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (decr_pc_after_break) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0regcache_write_pc (regcache, tmp_pc + >> decr_pc_after_break); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0return 1; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0return 0; >> + =A0 =A0} >> + >> + =A0return 1; >> +} >> + >> +static int >> +record_thread_wait_callback (struct thread_info *tp, void *data) >> +{ >> + =A0struct record_thread_wait_args *args =3D data; >> + =A0enum target_signal sig =3D TARGET_SIGNAL_0; >> + =A0int options =3D args->options; >> + =A0int ret; >> + >> + =A0if (tp->state_ =3D=3D THREAD_EXITED) >> + =A0 =A0return 0; >> + >> + =A0if (record_debug > 1) >> + =A0 =A0fprintf_unfiltered (gdb_stdlog, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Process record: record= _thread_wait_callback " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"resume %s\n", target_p= id_to_str (tp->ptid)); >> + >> + =A0inferior_ptid =3D tp->ptid; >> + >> + =A0if (!tp->record_is_waiting) >> + =A0 =A0{ >> + =A0 =A0 =A0if (record_resume_signal !=3D TARGET_SIGNAL_0 >> + =A0 =A0 =A0 =A0 =A0&& ptid_equal (inferior_ptid, args->real_inferior_p= tid)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0sig =3D record_resume_signal; >> + =A0 =A0 =A0 =A0 =A0record_resume_signal =3D TARGET_SIGNAL_0; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0if (!do_record_message (sig, 1)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0args->status->kind =3D TARGET_WAITKIND_STOPPED; >> + =A0 =A0 =A0 =A0 =A0args->status->value.sig =3D TARGET_SIGNAL_0; >> + =A0 =A0 =A0 =A0 =A0return 1; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0if (record_step =3D=3D 0) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0/* The next insn is a sys_clone. =A0*/ >> + =A0 =A0 =A0 =A0 =A0iterate_over_threads (record_thread_stop_callback, = NULL); >> + =A0 =A0 =A0 =A0 =A0non_stop =3D 0; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0record_beneath_to_resume (record_beneath_to_resume_ops, >> inferior_ptid, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0record_= step, sig); >> + =A0 =A0} >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0if (record_debug > 1) >> + =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Process record= : record_thread_wait_callback >> " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"not resume %s\= n", target_pid_to_str >> (tp->ptid)); >> + =A0 =A0} >> + >> + =A0if (record_step) >> + =A0 =A0options |=3D TARGET_WNOHANG; >> + =A0ret =3D record_thread_wait (inferior_ptid, args->status, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0options, NULL); >> + =A0if (args->status->kind =3D=3D TARGET_WAITKIND_IGNORE) >> + =A0 =A0{ >> + =A0 =A0 =A0if (!tp->record_is_waiting) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0tp->record_is_waiting =3D 1; >> + =A0 =A0 =A0 =A0 =A0if (record_debug > 1) >> + =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"Proces= s record: >> record_thread_wait_callback " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"start = waiting %s.\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 target_pid= _to_str (tp->ptid)); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0if (tp->record_is_waiting) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0tp->record_is_waiting =3D 0; >> + =A0 =A0 =A0 =A0 =A0if (record_debug > 1) >> + =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"Proces= s record: >> record_thread_wait_callback " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"stop w= aiting %s.\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 target_pid= _to_str (tp->ptid)); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0if (!args->real_inferior_tp >> + =A0 =A0 =A0 =A0 =A0&& ptid_equal (inferior_ptid, args->real_inferior_p= tid)) >> + =A0 =A0 =A0 =A0args->real_inferior_tp =3D tp; >> + =A0 =A0 =A0if (args->real_inferior_tp =3D=3D tp) >> + =A0 =A0 =A0 =A0args->real_inferior_status =3D *args->status; >> =A0 =A0 } >> + >> + =A0return ret; >> =A0} >> >> =A0static int record_get_sig =3D 0; >> @@ -1023,7 +1437,13 @@ record_sig_handler (int signo) >> =A0} >> >> =A0static void >> -record_wait_cleanups (void *ignore) >> +record_wait_signal_cleanups (void *ignore) >> +{ >> + =A0signal (SIGINT, handle_sigint); >> +} >> + >> +static void >> +record_wait_replay_cleanups (void *ignore) >> =A0{ >> =A0 if (execution_direction =3D=3D EXEC_REVERSE) >> =A0 =A0 { >> @@ -1034,6 +1454,17 @@ record_wait_cleanups (void *ignore) >> =A0 =A0 record_list =3D record_list->prev; >> =A0} >> >> +static void >> +record_wait_mthread_cleanups (void *ignore) >> +{ >> + =A0non_stop =3D 1; >> + >> + =A0/* Stop the threads that still running. =A0*/ >> + =A0iterate_over_threads (record_thread_stop_callback, NULL); >> + >> + =A0non_stop =3D 0; >> +} >> + >> =A0/* "to_wait" target method for process record target. >> >> =A0 =A0In record mode, the target is always run in singlestep mode >> @@ -1052,7 +1483,10 @@ record_wait (struct target_ops *ops, >> =A0 =A0 =A0 =A0 =A0 =A0 ptid_t ptid, struct target_waitstatus *status, >> =A0 =A0 =A0 =A0 =A0 =A0 int options) >> =A0{ >> + =A0ptid_t ret_ptid; >> =A0 struct cleanup *set_cleanups =3D record_gdb_operation_disable_set (); >> + =A0struct cleanup *signal_cleanups >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D make_cleanup (record_wait_s= ignal_cleanups, 0); >> >> =A0 if (record_debug) >> =A0 =A0 fprintf_unfiltered (gdb_stdlog, >> @@ -1060,93 +1494,112 @@ 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); >> >> + =A0record_get_sig =3D 0; >> + =A0signal (SIGINT, record_sig_handler); >> + >> =A0 if (!RECORD_IS_REPLAY && ops !=3D &record_core_ops) >> =A0 =A0 { >> - =A0 =A0 =A0if (record_resume_step) >> - =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 /* This is a single step. =A0*/ >> - =A0 =A0 =A0 =A0 return record_beneath_to_wait (record_beneath_to_wait_= ops, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0ptid, status, options); >> - =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/* Record mode. =A0*/ >> + =A0 =A0 =A0if (record_thread_number > 1 && !ptid_equal (record_resume_= ptid, >> + =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 inferior_ptid)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0/* Multi-threads record. =A0*/ >> + =A0 =A0 =A0 =A0 =A0struct record_thread_wait_args args; >> + =A0 =A0 =A0 =A0 =A0struct thread_info *tp; >> + =A0 =A0 =A0 =A0 =A0struct cleanup *mthread_cleanups >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D make_cleanu= p (record_wait_mthread_cleanups, >> 0); >> >> - =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, options); >> + =A0 =A0 =A0 =A0 =A0args.real_inferior_ptid =3D inferior_ptid; >> + =A0 =A0 =A0 =A0 =A0args.real_inferior_tp =3D NULL; >> + =A0 =A0 =A0 =A0 =A0args.status =3D status; >> + =A0 =A0 =A0 =A0 =A0args.options =3D options; >> + =A0 =A0 =A0 =A0 =A0non_stop =3D 1; >> + =A0 =A0 =A0 =A0 =A0iterate_over_threads (record_thread_reset_callback,= NULL); >> >> - =A0 =A0 =A0 =A0 =A0 =A0 /* Is this a SIGTRAP? =A0*/ >> - =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_SIG= NAL_TRAP) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct regcache *regcache; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct address_space *aspace; >> + =A0 =A0 =A0 =A0 =A0while (1) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0tp =3D iterate_over_threads (record_thread_= wait_callback, >> &args); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (tp) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_resume_step >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&& args.real_inferior_tp >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&& !args.real_inferior_tp->record_i= s_waiting) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*status =3D args.real_inferior_stat= us; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0inferior_ptid =3D args.real_inferio= r_ptid; >> + =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 =A0 /* Yes -- this is likely our single-st= ep finishing, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0but check if there's any reason= the core would be >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0interested in the event. =A0*/ >> + =A0 =A0 =A0 =A0 =A0do_cleanups (mthread_cleanups); >> >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 registers_changed (); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 regcache =3D get_current_regcache (); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 tmp_pc =3D regcache_read_pc (regcache); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 aspace =3D get_regcache_aspace (regcac= he); >> + =A0 =A0 =A0 =A0 =A0if (tp && tp->state_ !=3D THREAD_EXITED) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0inferior_ptid =3D tp->ptid; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0ret_ptid =3D inferior_ptid; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0/* Single-thread record. =A0*/ >> + =A0 =A0 =A0 =A0 =A0if (record_thread_number > 1) >> + =A0 =A0 =A0 =A0 =A0 =A0ptid =3D record_resume_ptid; >> >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (target_stopped_by_watchpoint ()) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Always interested in watchp= oints. =A0*/ >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 else if (breakpoint_inserted_here_p (a= space, 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 here.= =A0Let the core >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0handle it. =A0*/ >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (software_breakpoint_insert= ed_here_p (aspace, >> tmp_pc)) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct gdbarch *gdbarc= h =3D get_regcache_arch >> (regcache); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 CORE_ADDR decr_pc_afte= r_break >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D gdbarch_decr_p= c_after_break (gdbarch); >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (decr_pc_after_brea= k) >> - =A0 =A0 =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 =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 /* This must be a single-step = trap. =A0Record the >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0insn and issue another = step. =A0*/ >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!do_record_message (regcac= he, TARGET_SIGNAL_0, >> 1)) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 status->kind =3D T= ARGET_WAITKIND_STOPPED; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 status->value.sig = =3D TARGET_SIGNAL_0; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break; >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0if (record_resume_step) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 /* This is a single step. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 ret_ptid =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 =A0 =A0 =A0 ptid, status, options); >> + =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0/* This is not a single step. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0while (1) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_thread_wait (ptid, statu= s, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0options, &ret_ptid)) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_beneath_to_resume >> (record_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 TARGET_SIGNAL_0); >> - =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 =A0 =A0 =A0if (record_resume_step) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> >> - =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 =A0 =A0 =A0 =A0 =A0/* There is not a breakpoint, and g= db is not >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 stepping, therefore gdb will n= ot stop. >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Therefore we will not return t= o gdb. >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 Record the insn and resume. = =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!do_record_message (TARGET_SIGNAL_= 0, 1)) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ret_ptid =3D inferior_ptid; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0status->kind =3D TARGET_WAI= TKIND_STOPPED; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0status->value.sig =3D TARGE= T_SIGNAL_0; >> + =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 return ret; >> - =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_beneath_to_resume (record_benea= th_to_resume_ops, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 record_resume_ptid, >> record_step, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 TARGET_SIGNAL_0); >> + =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 =A0struct regcache *regcache =3D get_current_regcache (); >> - =A0 =A0 =A0struct gdbarch *gdbarch =3D get_regcache_arch (regcache); >> - =A0 =A0 =A0struct address_space *aspace =3D get_regcache_aspace (regca= che); >> + =A0 =A0 =A0/* Replay mode. =A0*/ >> + =A0 =A0 =A0struct regcache *regcache; >> + =A0 =A0 =A0struct gdbarch *gdbarch; >> + =A0 =A0 =A0struct address_space *aspace; >> =A0 =A0 =A0 int continue_flag =3D 1; >> =A0 =A0 =A0 int first_record_end =3D 1; >> - =A0 =A0 =A0struct cleanup *old_cleanups =3D make_cleanup (record_wait_= cleanups, >> 0); >> + =A0 =A0 =A0struct cleanup *old_cleanups =3D >> + =A0 =A0 =A0 =A0make_cleanup (record_wait_replay_cleanups, 0); >> =A0 =A0 =A0 CORE_ADDR tmp_pc; >> + =A0 =A0 =A0ptid_t old_inferior_ptid =3D inferior_ptid; >> + >> + =A0 =A0 =A0if (!ptid_equal (record_prev_ptid, null_ptid)) >> + =A0 =A0 =A0 =A0inferior_ptid =3D record_prev_ptid; >> + =A0 =A0 =A0regcache =3D get_current_regcache (); >> + =A0 =A0 =A0gdbarch =3D get_regcache_arch (regcache); >> + =A0 =A0 =A0aspace =3D get_regcache_aspace (regcache); >> >> =A0 =A0 =A0 record_hw_watchpoint =3D 0; >> =A0 =A0 =A0 status->kind =3D TARGET_WAITKIND_STOPPED; >> @@ -1173,8 +1626,6 @@ record_wait (struct target_ops *ops, >> =A0 =A0 =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 =A0And in GDB replay mode, GDB doesn't need to be in >> terminal_inferior >> =A0 =A0 =A0 =A0 =A0mode, because inferior will not executed. >> @@ -1205,7 +1656,7 @@ record_wait (struct target_ops *ops, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> =A0 =A0 =A0 =A0 =A0 =A0} >> >> - =A0 =A0 =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + =A0 =A0 =A0 =A0 =A0record_exec_insn (®cache, &gdbarch, &aspace, rec= ord_list); >> >> =A0 =A0 =A0 =A0 =A0if (record_list->type =3D=3D record_end) >> =A0 =A0 =A0 =A0 =A0 =A0{ >> @@ -1228,19 +1679,20 @@ record_wait (struct target_ops *ops, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 In EXEC_FORWARD mode, this is th= e record_end of >> current >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 instruction. =A0*/ >> =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 if (record_resume_step >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&& ptid_equal (inferior_pti= d, old_inferior_ptid)) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug > 1) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_s= tdlog, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =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 =A0continue_flag =3D 0; >> =A0 =A0 =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 =A0tmp_pc =3D regcache_read_pc (regcache= ); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (breakpoint_inserted_here_p (aspac= e, tmp_pc)) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int decr_pc_after_break >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 CORE_ADDR decr_pc_after_break >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D gdbarch_decr_pc_after= _break (gdbarch); >> >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> @@ -1288,22 +1740,23 @@ Process record: hit hw watchpoint.\n"); >> =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 while (continue_flag); >> >> - =A0 =A0 =A0signal (SIGINT, handle_sigint); >> - >> =A0replay_out: >> - =A0 =A0 =A0if (record_get_sig) >> - =A0 =A0 =A0 status->value.sig =3D TARGET_SIGNAL_INT; >> - =A0 =A0 =A0else if (record_list->u.end.sigval !=3D TARGET_SIGNAL_0) >> + =A0 =A0 =A0if (record_list->u.end.sigval !=3D TARGET_SIGNAL_0) >> =A0 =A0 =A0 =A0/* FIXME: better way to check */ >> =A0 =A0 =A0 =A0status->value.sig =3D record_list->u.end.sigval; >> =A0 =A0 =A0 else >> =A0 =A0 =A0 =A0status->value.sig =3D TARGET_SIGNAL_TRAP; >> + =A0 =A0 =A0ret_ptid =3D inferior_ptid; >> >> =A0 =A0 =A0 discard_cleanups (old_cleanups); >> =A0 =A0 } >> >> + =A0if (record_get_sig) >> + =A0 =A0status->value.sig =3D TARGET_SIGNAL_INT; >> + >> + =A0do_cleanups (signal_cleanups); >> =A0 do_cleanups (set_cleanups); >> - =A0return inferior_ptid; >> + =A0return ret_ptid; >> =A0} >> >> =A0static int >> @@ -1384,6 +1837,12 @@ record_registers_change (struct regcache >> =A0 record_arch_list_head =3D NULL; >> =A0 record_arch_list_tail =3D NULL; >> >> + =A0if (!ptid_equal (record_prev_ptid, inferior_ptid)) >> + =A0 =A0{ >> + =A0 =A0 =A0record_arch_list_add_ptid (&record_prev_ptid); >> + =A0 =A0 =A0record_prev_ptid =3D inferior_ptid; >> + =A0 =A0} >> + >> =A0 if (regnum < 0) >> =A0 =A0 { >> =A0 =A0 =A0 int i; >> @@ -1506,6 +1965,11 @@ record_xfer_partial (struct target_ops * >> =A0 =A0 =A0 /* Record registers change to list as an instruction. =A0*/ >> =A0 =A0 =A0 record_arch_list_head =3D NULL; >> =A0 =A0 =A0 record_arch_list_tail =3D NULL; >> + =A0 =A0 =A0if (!ptid_equal (record_prev_ptid, inferior_ptid)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0record_arch_list_add_ptid (&record_prev_ptid); >> + =A0 =A0 =A0 =A0 =A0record_prev_ptid =3D inferior_ptid; >> + =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 if (record_arch_list_add_mem (offset, len)) >> =A0 =A0 =A0 =A0{ >> =A0 =A0 =A0 =A0 =A0record_list_release (record_arch_list_tail); >> @@ -2061,6 +2525,17 @@ info_record_command (char *args, int fro >> =A0 =A0 =A0 =A04 bytes: memory length (network byte order). >> =A0 =A0 =A0 =A08 bytes: memory address (network byte order). >> =A0 =A0 =A0 =A0n bytes: memory value (n =3D=3D memory length). >> + =A0 =A0 record_mem: >> + =A0 =A0 =A0 1 byte: =A0record type (record_mem, see enum record_type). >> + =A0 =A0 =A0 4 bytes: memory length (network byte order). >> + =A0 =A0 =A0 8 bytes: memory address (network byte order). >> + =A0 =A0 =A0 n bytes: memory value (n =3D=3D memory length). >> + =A0 =A0 record_ptid: >> + =A0 =A0 =A0 1 byte: =A0record type (record_ptid, see enum record_type). >> + =A0 =A0 =A0 8 bytes: process id (network byte order). >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0It must same with CORELOW_PID (1). >> + =A0 =A0 =A0 8 bytes: lightweight process id (network byte order). >> + =A0 =A0 =A0 8 bytes: thread id (network byte order). >> >> =A0*/ >> >> @@ -2222,6 +2697,32 @@ record_restore (void) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0rec->u.me= m.len); >> =A0 =A0 =A0 =A0 =A0 break; >> >> + =A0 =A0 =A0 =A0case record_ptid: /* ptid */ >> + =A0 =A0 =A0 =A0 =A0rec =3D record_ptid_alloc (); >> + >> + =A0 =A0 =A0 =A0 /* Get Process id. =A0*/ >> + =A0 =A0 =A0 =A0 bfdcore_read (core_bfd, osec, &addr, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sizeof (addr), &bfd_offset= ); >> + =A0 =A0 =A0 =A0 rec->u.ptid.pid =3D (int) netorder64 (addr); >> + >> + =A0 =A0 =A0 =A0 /* Get Lightweight process id. =A0*/ >> + =A0 =A0 =A0 =A0 bfdcore_read (core_bfd, osec, &addr, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sizeof (addr), &bfd_offset= ); >> + =A0 =A0 =A0 =A0 rec->u.ptid.lwp =3D (long) netorder64 (addr); >> + >> + =A0 =A0 =A0 =A0 /* Get Thread id. =A0*/ >> + =A0 =A0 =A0 =A0 bfdcore_read (core_bfd, osec, &addr, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sizeof (addr), &bfd_offset= ); >> + =A0 =A0 =A0 =A0 rec->u.ptid.tid =3D (long) netorder64 (addr); >> + >> + =A0 =A0 =A0 =A0 if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, "\ >> + =A0Reading ptid %s (1 + 8 + 8 + 8 bytes), offset =3D=3D %s\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 target_pid= _to_str (record_list->u.ptid), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 paddress (= get_current_arch (), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 bfd_offset)); >> + =A0 =A0 =A0 =A0 =A0break; >> + >> =A0 =A0 =A0 =A0 case record_end: /* end */ >> =A0 =A0 =A0 =A0 =A0 rec =3D record_end_alloc (); >> =A0 =A0 =A0 =A0 =A0 record_insn_num ++; >> @@ -2327,6 +2828,7 @@ cmd_record_save (char *args, int from_tt >> =A0 uint32_t magic; >> =A0 struct regcache *regcache; >> =A0 struct gdbarch *gdbarch; >> + =A0struct address_space *aspace; >> =A0 struct cleanup *old_cleanups; >> =A0 struct cleanup *set_cleanups; >> =A0 bfd *obfd; >> @@ -2363,6 +2865,7 @@ cmd_record_save (char *args, int from_tt >> =A0 /* Get the values of regcache and gdbarch. =A0*/ >> =A0 regcache =3D get_current_regcache (); >> =A0 gdbarch =3D get_regcache_arch (regcache); >> + =A0aspace =3D get_regcache_aspace (regcache); >> >> =A0 /* Disable the GDB operation record. =A0*/ >> =A0 set_cleanups =3D record_gdb_operation_disable_set (); >> @@ -2374,7 +2877,7 @@ cmd_record_save (char *args, int from_tt >> =A0 =A0 =A0 if (record_list =3D=3D &record_first) >> =A0 =A0 =A0 =A0 break; >> >> - =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + =A0 =A0 =A0record_exec_insn (®cache, &gdbarch, &aspace, record_list= ); >> >> =A0 =A0 =A0 if (record_list->prev) >> =A0 =A0 =A0 =A0 record_list =3D record_list->prev; >> @@ -2395,6 +2898,9 @@ cmd_record_save (char *args, int from_tt >> =A0 =A0 =A0 case record_mem: >> =A0 =A0 =A0 =A0save_size +=3D 1 + 4 + 8 + record_list->u.mem.len; >> =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0case record_ptid: >> + =A0 =A0 =A0 save_size +=3D 1 + 8 + 8 + 8; >> + =A0 =A0 =A0 break; >> =A0 =A0 =A0 } >> >> =A0 /* Make the new bfd section. =A0*/ >> @@ -2481,6 +2987,25 @@ cmd_record_save (char *args, int from_tt >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 record_list->u.m= em.len, &bfd_offset); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 break; >> >> + =A0 =A0 =A0 =A0 =A0 =A0case record_ptid: /* ptid */ >> + =A0 =A0 =A0 =A0 =A0 =A0 if (record_debug) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fprintf_unfiltered (gdb_stdlog, "\ >> + =A0Writing ptid %s (1 plus 8 plus 8 plus 8 bytes)\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ta= rget_pid_to_str >> (record_list->u.ptid)); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 /* Write Process id. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 addr =3D netorder64 ((uint64_t) 1); >> + =A0 =A0 =A0 =A0 =A0 =A0 bfdcore_write (obfd, osec, &addr, sizeof (addr= ), >> &bfd_offset); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 /* Write Lightweight process id. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 addr =3D netorder64 ((uint64_t) record_list->u= .ptid.lwp); >> + =A0 =A0 =A0 =A0 =A0 =A0 bfdcore_write (obfd, osec, &addr, sizeof (addr= ), >> &bfd_offset); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 /* Write Thread id. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 addr =3D netorder64 ((uint64_t) record_list->u= .ptid.tid); >> + =A0 =A0 =A0 =A0 =A0 =A0 bfdcore_write (obfd, osec, &addr, sizeof (addr= ), >> &bfd_offset); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 case record_end: >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (record_debug) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf_unfiltered (gdb_stdlog, "\ >> @@ -2501,7 +3026,7 @@ cmd_record_save (char *args, int from_tt >> =A0 =A0 =A0 =A0 } >> >> =A0 =A0 =A0 /* Execute entry. =A0*/ >> - =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + =A0 =A0 =A0record_exec_insn (®cache, &gdbarch, &aspace, record_list= ); >> >> =A0 =A0 =A0 if (record_list->next) >> =A0 =A0 =A0 =A0 record_list =3D record_list->next; >> @@ -2516,7 +3041,7 @@ cmd_record_save (char *args, int from_tt >> =A0 =A0 =A0 if (record_list =3D=3D cur_record_list) >> =A0 =A0 =A0 =A0 break; >> >> - =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + =A0 =A0 =A0record_exec_insn (®cache, &gdbarch, &aspace, record_list= ); >> >> =A0 =A0 =A0 if (record_list->prev) >> =A0 =A0 =A0 =A0 record_list =3D record_list->prev; >> @@ -2542,6 +3067,7 @@ record_goto_insn (struct record_entry *e >> =A0 struct cleanup *set_cleanups =3D record_gdb_operation_disable_set (); >> =A0 struct regcache *regcache =3D get_current_regcache (); >> =A0 struct gdbarch *gdbarch =3D get_regcache_arch (regcache); >> + =A0struct address_space *aspace =3D get_regcache_aspace (regcache); >> >> =A0 /* Assume everything is valid: we will hit the entry, >> =A0 =A0 =A0and we will not hit the end of the recording. =A0*/ >> @@ -2551,7 +3077,7 @@ record_goto_insn (struct record_entry *e >> >> =A0 do >> =A0 =A0 { >> - =A0 =A0 =A0record_exec_insn (regcache, gdbarch, record_list); >> + =A0 =A0 =A0record_exec_insn (®cache, &gdbarch, &aspace, record_list= ); >> =A0 =A0 =A0 if (dir =3D=3D EXEC_REVERSE) >> =A0 =A0 =A0 =A0record_list =3D record_list->prev; >> =A0 =A0 =A0 else >> --- a/record.h >> +++ b/record.h >> @@ -23,6 +23,7 @@ >> =A0#define RECORD_IS_USED (current_target.to_stratum =3D=3D record_strat= um) >> >> =A0extern int record_debug; >> +extern int record_step; >> >> =A0extern int record_arch_list_add_reg (struct regcache *regcache, int n= um); >> =A0extern int record_arch_list_add_mem (CORE_ADDR addr, int len); > >