From: Hui Zhu <teawater@gmail.com>
To: gdb-patches ml <gdb-patches@sourceware.org>
Cc: Michael Snyder <msnyder@vmware.com>, tromey@redhat.com
Subject: Re: [RFC] Prec multi-thread support
Date: Thu, 12 Nov 2009 08:26:00 -0000 [thread overview]
Message-ID: <daef60380911120025g3d20d304qb82d2519f2ceee6e@mail.gmail.com> (raw)
In-Reply-To: <m3ocnbinor.fsf@fleche.redhat.com>
[-- Attachment #1: Type: text/plain, Size: 280 bytes --]
Hi guys,
This is the new version for multi-thread support. It make
multi-thread work OK with record save and support thread exit when
record.
I think the code work of prec multi-thread support is done. I can
begin to do some make it clear and some other things.
Thanks,
Hui
[-- Attachment #2: prec-x86-add-insn.txt --]
[-- Type: text/plain, Size: 734 bytes --]
---
i386-tdep.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
--- a/i386-tdep.c
+++ b/i386-tdep.c
@@ -4847,9 +4847,6 @@ reswitch:
/* int3 */
/* XXX */
case 0xcc:
- printf_unfiltered (_("Process record doesn't support instruction "
- "int3.\n"));
- ir.addr -= 1;
goto no_support;
break;
@@ -4958,10 +4955,8 @@ reswitch:
/* rdtsc */
case 0x0f31:
- printf_unfiltered (_("Process record doesn't support "
- "instruction rdtsc.\n"));
- ir.addr -= 2;
- goto no_support;
+ I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REAX_REGNUM);
+ I386_RECORD_ARCH_LIST_ADD_REG (X86_RECORD_REDX_REGNUM);
break;
/* sysenter */
[-- Attachment #3: prec-thread.txt --]
[-- Type: text/plain, Size: 39182 bytes --]
---
amd64-linux-tdep.c | 4
gdbthread.h | 11
i386-linux-tdep.c | 4
i386-tdep.c | 52 ++--
i386-tdep.h | 6
linux-record.c | 13 -
linux-record.h | 2
record.c | 675 +++++++++++++++++++++++++++++++++++++++++++++--------
record.h | 1
thread.c | 9
10 files changed, 641 insertions(+), 136 deletions(-)
--- a/amd64-linux-tdep.c
+++ b/amd64-linux-tdep.c
@@ -1155,7 +1155,7 @@ static struct linux_record_tdep amd64_li
#define RECORD_ARCH_GET_GS 0x1004
static int
-amd64_linux_syscall_record (struct regcache *regcache)
+amd64_linux_syscall_record (struct regcache *regcache, CORE_ADDR addr)
{
int ret;
ULONGEST syscall_native;
@@ -1205,7 +1205,7 @@ amd64_linux_syscall_record (struct regca
}
else
{
- ret = record_linux_system_call (syscall_gdb, regcache,
+ ret = record_linux_system_call (syscall_gdb, addr, regcache,
&amd64_linux_record_tdep);
if (ret)
return ret;
--- a/gdbthread.h
+++ b/gdbthread.h
@@ -29,6 +29,15 @@ struct symtab;
#include "ui-out.h"
#include "inferior.h"
+/* Frontend view of the thread state. Possible extensions: stepping,
+ finishing, until(ling),... */
+enum thread_state
+{
+ THREAD_STOPPED,
+ THREAD_RUNNING,
+ THREAD_EXITED,
+};
+
struct thread_info
{
struct thread_info *next;
@@ -37,6 +46,8 @@ struct thread_info
kernel thread id, etc. */
int num; /* Convenient handle (GDB thread id) */
+ int record_is_waiting;
+
/* Non-zero means the thread is executing. Note: this is different
from saying that there is an active target and we are stopped at
a breakpoint, for instance. This is a real indicator whether the
--- a/i386-linux-tdep.c
+++ b/i386-linux-tdep.c
@@ -411,7 +411,7 @@ i386_canonicalize_syscall (int syscall)
static struct linux_record_tdep i386_linux_record_tdep;
static int
-i386_linux_intx80_sysenter_record (struct regcache *regcache)
+i386_linux_intx80_sysenter_record (struct regcache *regcache, CORE_ADDR addr)
{
int ret;
LONGEST syscall_native;
@@ -437,7 +437,7 @@ i386_linux_intx80_sysenter_record (struc
return 0;
}
- ret = record_linux_system_call (syscall_gdb, regcache,
+ ret = record_linux_system_call (syscall_gdb, addr, regcache,
&i386_linux_record_tdep);
if (ret)
return ret;
--- a/i386-tdep.c
+++ b/i386-tdep.c
@@ -3160,10 +3160,11 @@ i386_record_lea_modrm (struct i386_recor
if (irp->override >= 0)
{
- warning (_("Process record ignores the memory change "
- "of instruction at address %s because it "
- "can't get the value of the segment register."),
- paddress (gdbarch, irp->orig_addr));
+ if (record_debug)
+ warning (_("Process record ignores the memory change "
+ "of instruction at address %s because it "
+ "can't get the value of the segment register."),
+ paddress (gdbarch, irp->orig_addr));
return 0;
}
@@ -4042,11 +4043,12 @@ reswitch:
case 0xa3:
if (ir.override >= 0)
{
- warning (_("Process record ignores the memory change "
- "of instruction at address %s because "
- "it can't get the value of the segment "
- "register."),
- paddress (gdbarch, ir.orig_addr));
+ if (record_debug)
+ warning (_("Process record ignores the memory change "
+ "of instruction at address %s because "
+ "it can't get the value of the segment "
+ "register."),
+ paddress (gdbarch, ir.orig_addr));
}
else
{
@@ -4467,11 +4469,12 @@ reswitch:
if (ir.aflag && (es != ds))
{
/* addr += ((uint32_t) read_register (I386_ES_REGNUM)) << 4; */
- warning (_("Process record ignores the memory "
- "change of instruction at address %s "
- "because it can't get the value of the "
- "ES segment register."),
- paddress (gdbarch, ir.orig_addr));
+ if (record_debug)
+ warning (_("Process record ignores the memory "
+ "change of instruction at address %s "
+ "because it can't get the value of the "
+ "ES segment register."),
+ paddress (gdbarch, ir.orig_addr));
}
else
{
@@ -4873,7 +4876,7 @@ reswitch:
ir.addr -= 2;
goto no_support;
}
- ret = gdbarch_tdep (gdbarch)->i386_intx80_record (ir.regcache);
+ ret = gdbarch_tdep (gdbarch)->i386_intx80_record (ir.regcache, ir.addr);
if (ret)
return ret;
}
@@ -4975,7 +4978,8 @@ reswitch:
ir.addr -= 2;
goto no_support;
}
- ret = gdbarch_tdep (gdbarch)->i386_sysenter_record (ir.regcache);
+ ret = gdbarch_tdep (gdbarch)->i386_sysenter_record (ir.regcache,
+ ir.addr);
if (ret)
return ret;
}
@@ -5000,7 +5004,8 @@ reswitch:
ir.addr -= 2;
goto no_support;
}
- ret = gdbarch_tdep (gdbarch)->i386_syscall_record (ir.regcache);
+ ret = gdbarch_tdep (gdbarch)->i386_syscall_record (ir.regcache,
+ ir.addr);
if (ret)
return ret;
}
@@ -5136,12 +5141,13 @@ reswitch:
/* sidt */
if (ir.override >= 0)
{
- warning (_("Process record ignores the memory "
- "change of instruction at "
- "address %s because it can't get "
- "the value of the segment "
- "register."),
- paddress (gdbarch, ir.orig_addr));
+ if (record_debug)
+ warning (_("Process record ignores the memory "
+ "change of instruction at "
+ "address %s because it can't get "
+ "the value of the segment "
+ "register."),
+ paddress (gdbarch, ir.orig_addr));
}
else
{
--- a/i386-tdep.h
+++ b/i386-tdep.h
@@ -115,11 +115,11 @@ struct gdbarch_tdep
in GDB is not same as I386 instructions. */
const int *record_regmap;
/* Parse intx80 args. */
- int (*i386_intx80_record) (struct regcache *regcache);
+ int (*i386_intx80_record) (struct regcache *regcache, CORE_ADDR addr);
/* Parse sysenter args. */
- int (*i386_sysenter_record) (struct regcache *regcache);
+ int (*i386_sysenter_record) (struct regcache *regcache, CORE_ADDR addr);
/* Parse syscall args. */
- int (*i386_syscall_record) (struct regcache *regcache);
+ int (*i386_syscall_record) (struct regcache *regcache, CORE_ADDR addr);
};
/* Floating-point registers. */
--- a/linux-record.c
+++ b/linux-record.c
@@ -21,6 +21,7 @@
#include "target.h"
#include "gdbtypes.h"
#include "regcache.h"
+#include "inferior.h"
#include "record.h"
#include "linux-record.h"
@@ -222,7 +223,7 @@ record_linux_msghdr (struct regcache *re
Return -1 if something wrong. */
int
-record_linux_system_call (enum gdb_syscall syscall,
+record_linux_system_call (enum gdb_syscall syscall, CORE_ADDR addr,
struct regcache *regcache,
struct linux_record_tdep *tdep)
{
@@ -242,8 +243,9 @@ record_linux_system_call (enum gdb_sysca
int q;
target_terminal_ours ();
q = yquery (_("The next instruction is syscall exit. "
- "It will make the program exit. "
- "Do you want to stop the program?"));
+ "It will make the thread %s exit. "
+ "Do you want to stop the program?"),
+ target_pid_to_str (inferior_ptid));
target_terminal_inferior ();
if (q)
return 1;
@@ -1209,10 +1211,13 @@ record_linux_system_call (enum gdb_sysca
case gdb_sys_fsync:
case gdb_sys_sigreturn:
- case gdb_sys_clone:
case gdb_sys_setdomainname:
break;
+ case gdb_sys_clone:
+ record_step = 0;
+ break;
+
case gdb_sys_newuname:
regcache_raw_read_unsigned (regcache, tdep->arg1, &tmpulongest);
if (record_arch_list_add_mem ((CORE_ADDR) tmpulongest,
--- a/linux-record.h
+++ b/linux-record.h
@@ -534,7 +534,7 @@ enum gdb_syscall {
/* Record a linux syscall. */
-extern int record_linux_system_call (enum gdb_syscall num,
+extern int record_linux_system_call (enum gdb_syscall num, CORE_ADDR addr,
struct regcache *regcache,
struct linux_record_tdep *tdep);
#endif /* _LINUX_RECORD_H_ */
--- a/record.c
+++ b/record.c
@@ -30,6 +30,7 @@
#include "record.h"
#include "elf-bfd.h"
#include "gcore.h"
+#include "observer.h"
#include <signal.h>
@@ -60,6 +61,8 @@
#define RECORD_FILE_MAGIC netorder32(0x20091016)
+#define RECORD_THREAD (record_ops.beneath->to_stratum == thread_stratum)
+
/* These are the core structs of the process record functionality.
A record_entry is a record of the value change of a register
@@ -106,7 +109,8 @@ enum record_type
{
record_end = 0,
record_reg,
- record_mem
+ record_mem,
+ record_ptid
};
/* This is the data structure that makes up the execution log.
@@ -144,6 +148,8 @@ struct record_entry
struct record_reg_entry reg;
/* mem */
struct record_mem_entry mem;
+ /* ptid */
+ ptid_t ptid;
/* end */
struct record_end_entry end;
} u;
@@ -196,10 +202,19 @@ static int record_insn_num = 0;
than count of insns presently in execution log). */
static ULONGEST record_insn_count;
+/* In record mode, it's the step of next resume. */
+int record_step;
+
+/* The current inferior_ptid that is recorded. */
+static ptid_t record_prev_ptid;
+
/* The target_ops of process record. */
static struct target_ops record_ops;
static struct target_ops record_core_ops;
+static struct observer *record_new_thread_observer = NULL;
+static struct observer *record_thread_exit_observer = NULL;
+
/* The beneath function pointers. */
static struct target_ops *record_beneath_to_resume_ops;
static void (*record_beneath_to_resume) (struct target_ops *, ptid_t, int,
@@ -285,6 +300,27 @@ record_mem_release (struct record_entry
xfree (rec);
}
+/* Alloc a record_ptid record entry. */
+
+static inline struct record_entry *
+record_ptid_alloc (void)
+{
+ struct record_entry *rec;
+
+ rec = (struct record_entry *) xcalloc (1, sizeof (struct record_entry));
+ rec->type = record_ptid;
+
+ return rec;
+}
+
+/* Free a record_ptid record entry. */
+
+static inline void
+record_ptid_release (struct record_entry *rec)
+{
+ xfree (rec);
+}
+
/* Alloc a record_end record entry. */
static inline struct record_entry *
@@ -321,6 +357,9 @@ record_entry_release (struct record_entr
case record_mem:
record_mem_release (rec);
break;
+ case record_ptid:
+ record_ptid_release (rec);
+ break;
case record_end:
record_end_release (rec);
break;
@@ -328,6 +367,16 @@ record_entry_release (struct record_entr
return type;
}
+/* Remove one record entry from record_list. */
+
+static void
+record_entry_remove_from_list (struct record_entry *rec)
+{
+ if (rec->next)
+ rec->next->prev = rec->prev;
+ rec->prev->next = rec->next;
+}
+
/* Free all record entries in list pointed to by REC. */
static void
@@ -509,6 +558,24 @@ record_arch_list_add_mem (CORE_ADDR addr
return 0;
}
+static void
+record_arch_list_add_ptid (ptid_t *ptid)
+{
+ struct record_entry *rec;
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: add ptid = %s to "
+ "record list.\n",
+ target_pid_to_str (*ptid));
+
+ rec = record_ptid_alloc ();
+
+ rec->u.ptid = *ptid;
+
+ record_arch_list_add (rec);
+}
+
/* Add a record_end type struct record_entry to record_arch_list. */
int
@@ -570,7 +637,6 @@ record_arch_list_cleanups (void *ignore)
record_arch_list, and add it to record_list. */
struct record_message_args {
- struct regcache *regcache;
enum target_signal signal;
};
@@ -579,15 +645,21 @@ record_message (void *args)
{
int ret;
struct record_message_args *myargs = args;
- struct gdbarch *gdbarch = get_regcache_arch (myargs->regcache);
+ struct regcache *regcache;
+ struct gdbarch *gdbarch;
struct cleanup *old_cleanups = make_cleanup (record_arch_list_cleanups, 0);
+ record_step = 1;
+
record_arch_list_head = NULL;
record_arch_list_tail = NULL;
/* Check record_insn_num. */
record_check_insn_num (1);
+ regcache = get_current_regcache ();
+ gdbarch = get_regcache_arch (regcache);
+
/* If gdb sends a signal value to target_resume,
save it in the 'end' field of the previous instruction.
@@ -610,20 +682,45 @@ record_message (void *args)
But we should still deliver the signal to gdb during the replay,
if we delivered it during the recording. Therefore we should
record the signal during record_wait, not record_resume. */
- if (record_list != &record_first) /* FIXME better way to check */
+ if (ptid_equal (record_prev_ptid, inferior_ptid))
{
- gdb_assert (record_list->type == record_end);
- record_list->u.end.sigval = myargs->signal;
+ if (myargs->signal != TARGET_SIGNAL_0)
+ {
+ gdb_assert (record_list->type == record_end);
+ record_list->u.end.sigval = myargs->signal;
+ }
+ }
+ else
+ {
+ if (myargs->signal != TARGET_SIGNAL_0)
+ {
+ struct record_entry *rec;
+ for (rec = record_list; rec != record_first.next; rec = rec->prev)
+ {
+ if (rec->type == record_ptid
+ && ptid_equal (rec->u.ptid, inferior_ptid))
+ {
+ gdb_assert (rec->prev->type == record_end);
+ rec->prev->u.end.sigval = myargs->signal;
+ break;
+ }
+ }
+ }
+
+ /* If the inferior_ptid change (inferior_ptid is not same with
+ record_prev_ptid), record record_prev_ptid to record list. */
+ record_arch_list_add_ptid (&record_prev_ptid);
+ record_prev_ptid = inferior_ptid;
}
if (myargs->signal == TARGET_SIGNAL_0
|| !gdbarch_process_record_signal_p (gdbarch))
ret = gdbarch_process_record (gdbarch,
- myargs->regcache,
- regcache_read_pc (myargs->regcache));
+ regcache,
+ regcache_read_pc (regcache));
else
ret = gdbarch_process_record_signal (gdbarch,
- myargs->regcache,
+ regcache,
myargs->signal);
if (ret > 0)
@@ -646,12 +743,10 @@ record_message (void *args)
}
static int
-do_record_message (struct regcache *regcache,
- enum target_signal signal, int catch)
+do_record_message (enum target_signal signal, int catch)
{
struct record_message_args args;
- args.regcache = regcache;
args.signal = signal;
if (catch)
@@ -682,9 +777,12 @@ record_gdb_operation_disable_set (void)
entries and memory entries, followed by an 'end' entry. */
static inline void
-record_exec_insn (struct regcache *regcache, struct gdbarch *gdbarch,
+record_exec_insn (struct regcache **regcache_p, struct gdbarch **gdbarch_p,
struct record_entry *entry)
{
+ struct regcache *regcache = *regcache_p;
+ struct gdbarch *gdbarch = *gdbarch_p;
+
switch (entry->type)
{
case record_reg: /* reg */
@@ -748,6 +846,103 @@ record_exec_insn (struct regcache *regca
}
}
break;
+
+ case record_ptid: /* ptid */
+ {
+ ptid_t tmp_ptid;
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_ptid %s to "
+ "inferior ptid = %s.\n",
+ host_address_to_string (entry),
+ target_pid_to_str (entry->u.ptid));
+
+ if (!ptid_equal (entry->u.ptid, null_ptid))
+ {
+ inferior_ptid = entry->u.ptid;
+ *regcache_p = get_current_regcache ();
+ *gdbarch_p = get_regcache_arch (*regcache_p);
+ }
+ tmp_ptid = entry->u.ptid;
+ entry->u.ptid = record_prev_ptid;
+ record_prev_ptid = tmp_ptid;
+ }
+ break;
+ }
+}
+
+static int record_thread_number;
+
+static int
+record_thread_number_count (struct thread_info *thread, void *unused)
+{
+ if (thread->state_ != THREAD_EXITED)
+ record_thread_number ++;
+
+ return 0;
+}
+
+static void
+record_thread_number_reset (void)
+{
+ record_thread_number = 0;
+
+ if (RECORD_THREAD)
+ iterate_over_threads (record_thread_number_count, NULL);
+}
+
+static void
+record_new_thread_handler (struct thread_info *tp)
+{
+ tp->record_is_waiting = 0;
+
+ record_thread_number_reset ();
+}
+
+static void
+record_thread_exit_handler (struct thread_info *tp, int silent)
+{
+ struct record_entry *rec;
+ ptid_t cur_ptid = record_prev_ptid;
+
+ if (!record_first.next)
+ return;
+
+ tp->record_is_waiting = 0;
+
+ if (tp->state_ != THREAD_EXITED)
+ {
+ gdb_assert (record_thread_number > 0);
+ record_thread_number --;
+ }
+
+ /* Delete all the record_reg and record_ptid for tp->ptid
+ from record list. */
+ for (rec = record_list; rec != &record_first;)
+ {
+ struct record_entry *tmp = rec;
+ rec = rec->prev;
+
+ switch (tmp->type) {
+ case record_reg:
+ /* If this record_reg is for tp->ptid, delte it. */
+ if (ptid_equal (cur_ptid, tp->ptid))
+ {
+ record_entry_remove_from_list (tmp);
+ record_entry_release (tmp);
+ }
+ break;
+ case record_ptid:
+ /* If this record_ptid is for tp->ptid, delte it. */
+ cur_ptid = tmp->u.ptid;
+ if (ptid_equal (cur_ptid, tp->ptid))
+ {
+ record_entry_remove_from_list (tmp);
+ record_entry_release (tmp);
+ }
+ break;
+ }
}
}
@@ -842,6 +1037,9 @@ record_open_1 (char *name, int from_tty)
error (_("Could not find 'to_remove_breakpoint' method on the target stack."));
push_target (&record_ops);
+
+ record_new_thread_observer = observer_attach_new_thread (record_new_thread_handler);
+ record_thread_exit_observer = observer_attach_thread_exit (record_thread_exit_handler);
}
/* "to_open" target method. Open the process record target. */
@@ -907,6 +1105,7 @@ record_open (char *name, int from_tty)
record_insn_count = 0;
record_list = &record_first;
record_list->next = NULL;
+ record_prev_ptid = null_ptid;
/* Set the tmp beneath pointers to beneath pointers. */
record_beneath_to_resume_ops = tmp_to_resume_ops;
@@ -924,6 +1123,8 @@ record_open (char *name, int from_tty)
record_core_open_1 (name, from_tty);
else
record_open_1 (name, from_tty);
+
+ record_thread_number_reset ();
}
/* "to_close" target method. Close the process record target. */
@@ -936,6 +1137,17 @@ record_close (int quitting)
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "Process record: record_close\n");
+ if (record_new_thread_observer)
+ {
+ observer_detach_new_thread (record_new_thread_observer);
+ record_new_thread_observer = NULL;
+ }
+ if (record_thread_exit_observer)
+ {
+ observer_detach_thread_exit (record_thread_exit_observer);
+ record_thread_exit_observer = NULL;
+ }
+
record_list_release (record_list);
/* Release record_core_regbuf. */
@@ -958,6 +1170,8 @@ record_close (int quitting)
}
static int record_resume_step = 0;
+static ptid_t record_resume_ptid;
+static enum target_signal record_resume_signal = TARGET_SIGNAL_0;
/* "to_resume" target method. Resume the process record target. */
@@ -969,12 +1183,189 @@ record_resume (struct target_ops *ops, p
if (!RECORD_IS_REPLAY)
{
- do_record_message (get_current_regcache (), signal, 0);
- record_beneath_to_resume (record_beneath_to_resume_ops, ptid, 1,
- signal);
+ record_resume_ptid = ptid;
+ if (record_thread_number > 1 && !ptid_equal (ptid, inferior_ptid))
+ {
+ record_resume_signal = signal;
+ }
+ else
+ {
+ do_record_message (signal, 0);
+ record_beneath_to_resume (record_beneath_to_resume_ops, ptid,
+ record_step, signal);
+ }
}
}
+struct record_thread_wait_args {
+ ptid_t real_inferior_ptid;
+ struct thread_info *real_inferior_tp;
+ struct target_waitstatus real_inferior_status;
+
+ struct target_waitstatus *status;
+ int options;
+};
+
+static int
+record_thread_reset_callback (struct thread_info *tp, void *data)
+{
+ tp->record_is_waiting = 0;
+
+ return 0;
+}
+
+static int
+record_thread_check_callback (struct thread_info *tp, void *data)
+{
+ if (tp->state_ != THREAD_EXITED && tp->record_is_waiting)
+ return 1;
+
+ return 0;
+}
+
+/* Return 1 if it is not a simple step.
+ Return 0 if it is a simple step. */
+
+static int
+record_thread_wait (ptid_t ptid, struct target_waitstatus *status,
+ int options, ptid_t *ret_ptid)
+{
+ ptid_t wait_ptid = record_beneath_to_wait (record_beneath_to_wait_ops,
+ ptid, status, options);
+
+ if (ret_ptid)
+ *ret_ptid = wait_ptid;
+
+ if (status->kind == TARGET_WAITKIND_IGNORE)
+ return 0;
+
+ inferior_ptid = wait_ptid;
+
+ /* Is this a SIGTRAP? */
+ if (status->kind == TARGET_WAITKIND_STOPPED
+ && status->value.sig == TARGET_SIGNAL_TRAP)
+ {
+ CORE_ADDR tmp_pc;
+ struct regcache *regcache;
+ struct gdbarch *gdbarch;
+
+ /* Yes -- check if there is a breakpoint. */
+ registers_changed ();
+ regcache = get_current_regcache ();
+ gdbarch = get_regcache_arch (regcache);
+ tmp_pc = regcache_read_pc (regcache);
+ if (!record_step)
+ tmp_pc -= gdbarch_decr_pc_after_break (gdbarch);
+ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), tmp_pc))
+ {
+ /* There is a breakpoint. GDB will want to stop. */
+ if (record_step)
+ {
+ CORE_ADDR decr_pc_after_break
+ = gdbarch_decr_pc_after_break (gdbarch);
+ if (decr_pc_after_break)
+ regcache_write_pc (regcache, tmp_pc + decr_pc_after_break);
+ }
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+record_thread_wait_callback (struct thread_info *tp, void *data)
+{
+ struct record_thread_wait_args *args = data;
+ enum target_signal sig = TARGET_SIGNAL_0;
+ int options = args->options;
+ int ret;
+
+ if (tp->state_ == THREAD_EXITED)
+ return 0;
+
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_thread_wait_callback "
+ "resume %s\n", target_pid_to_str (tp->ptid));
+
+ inferior_ptid = tp->ptid;
+
+ if (!tp->record_is_waiting)
+ {
+ if (record_resume_signal != TARGET_SIGNAL_0
+ && ptid_equal (inferior_ptid, args->real_inferior_ptid))
+ {
+ sig = record_resume_signal;
+ record_resume_signal = TARGET_SIGNAL_0;
+ }
+ if (!do_record_message (sig, 1))
+ {
+ args->status->kind = TARGET_WAITKIND_STOPPED;
+ args->status->value.sig = TARGET_SIGNAL_0;
+ return 1;
+ }
+
+ if (record_step == 0)
+ {
+ /* The next insn is a sys_clone. */
+ if (iterate_over_threads (record_thread_check_callback, NULL))
+ target_stop (minus_one_ptid);
+ non_stop = 0;
+ }
+
+ record_beneath_to_resume (record_beneath_to_resume_ops, inferior_ptid,
+ record_step, sig);
+ }
+ else
+ {
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_thread_wait_callback "
+ "not resume %s\n", target_pid_to_str (tp->ptid));
+ }
+
+ if (record_step)
+ options |= TARGET_WNOHANG;
+ ret = record_thread_wait (inferior_ptid, args->status,
+ options, NULL);
+ if (args->status->kind == TARGET_WAITKIND_IGNORE)
+ {
+ if (!tp->record_is_waiting)
+ {
+ tp->record_is_waiting = 1;
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_thread_wait_callback "
+ "start waiting %s.\n",
+ target_pid_to_str (tp->ptid));
+ }
+ }
+ else
+ {
+ if (tp->record_is_waiting)
+ {
+ tp->record_is_waiting = 0;
+ if (record_debug > 1)
+ fprintf_unfiltered (gdb_stdlog,
+ "Process record: record_thread_wait_callback "
+ "stop waiting %s.\n",
+ target_pid_to_str (tp->ptid));
+ }
+
+ if (!args->real_inferior_tp
+ && ptid_equal (inferior_ptid, args->real_inferior_ptid))
+ args->real_inferior_tp = tp;
+ if (args->real_inferior_tp == tp)
+ args->real_inferior_status = *args->status;
+ }
+
+ return ret;
+}
+
static int record_get_sig = 0;
/* SIGINT signal handler, registered by "to_wait" method. */
@@ -994,7 +1385,13 @@ record_sig_handler (int signo)
}
static void
-record_wait_cleanups (void *ignore)
+record_wait_signal_cleanups (void *ignore)
+{
+ signal (SIGINT, handle_sigint);
+}
+
+static void
+record_wait_replay_cleanups (void *ignore)
{
if (execution_direction == EXEC_REVERSE)
{
@@ -1005,6 +1402,16 @@ record_wait_cleanups (void *ignore)
record_list = record_list->prev;
}
+static void
+record_wait_mthread_cleanups (void *ignore)
+{
+ /* Stop the threads that still running. */
+ if (iterate_over_threads (record_thread_check_callback, NULL))
+ target_stop (minus_one_ptid);
+
+ non_stop = 0;
+}
+
/* "to_wait" target method for process record target.
In record mode, the target is always run in singlestep mode
@@ -1023,7 +1430,10 @@ record_wait (struct target_ops *ops,
ptid_t ptid, struct target_waitstatus *status,
int options)
{
+ ptid_t ret_ptid;
struct cleanup *set_cleanups = record_gdb_operation_disable_set ();
+ struct cleanup *signal_cleanups
+ = make_cleanup (record_wait_signal_cleanups, 0);
if (record_debug)
fprintf_unfiltered (gdb_stdlog,
@@ -1031,81 +1441,103 @@ record_wait (struct target_ops *ops,
"record_resume_step = %d\n",
record_resume_step);
+ record_get_sig = 0;
+ signal (SIGINT, record_sig_handler);
+
if (!RECORD_IS_REPLAY && ops != &record_core_ops)
{
- if (record_resume_step)
- {
- /* This is a single step. */
- return record_beneath_to_wait (record_beneath_to_wait_ops,
- ptid, status, options);
- }
- else
- {
- /* This is not a single step. */
- ptid_t ret;
- CORE_ADDR tmp_pc;
-
- while (1)
- {
- ret = record_beneath_to_wait (record_beneath_to_wait_ops,
- ptid, status, options);
+ /* Record mode. */
+ if (record_thread_number > 1 && !ptid_equal (record_resume_ptid,
+ inferior_ptid))
+ {
+ /* Multi-threads record. */
+ struct record_thread_wait_args args;
+ struct thread_info *tp;
+ struct cleanup *mthread_cleanups
+ = make_cleanup (record_wait_mthread_cleanups, 0);
- /* Is this a SIGTRAP? */
- if (status->kind == TARGET_WAITKIND_STOPPED
- && status->value.sig == TARGET_SIGNAL_TRAP)
- {
- struct regcache *regcache;
+ args.real_inferior_ptid = inferior_ptid;
+ args.real_inferior_tp = NULL;
+ args.status = status;
+ args.options = options;
+ non_stop = 1;
+ iterate_over_threads (record_thread_reset_callback, NULL);
- /* Yes -- check if there is a breakpoint. */
- registers_changed ();
- regcache = get_current_regcache ();
- tmp_pc = regcache_read_pc (regcache);
- if (breakpoint_inserted_here_p (get_regcache_aspace (regcache),
- tmp_pc))
- {
- /* There is a breakpoint. GDB will want to stop. */
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- CORE_ADDR decr_pc_after_break
- = gdbarch_decr_pc_after_break (gdbarch);
- if (decr_pc_after_break)
- regcache_write_pc (regcache,
- tmp_pc + decr_pc_after_break);
- }
- else
- {
- /* There is not a breakpoint, and gdb is not
- stepping, therefore gdb will not stop.
- Therefore we will not return to gdb.
- Record the insn and resume. */
- if (!do_record_message (regcache, TARGET_SIGNAL_0, 1))
- {
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = TARGET_SIGNAL_0;
- break;
- }
+ while (1)
+ {
+ tp = iterate_over_threads (record_thread_wait_callback, &args);
+ if (tp)
+ break;
+ if (record_resume_step
+ && args.real_inferior_tp
+ && !args.real_inferior_tp->record_is_waiting)
+ {
+ *status = args.real_inferior_status;
+ inferior_ptid = args.real_inferior_ptid;
+ break;
+ }
+ }
- record_beneath_to_resume (record_beneath_to_resume_ops,
- ptid, 1,
- TARGET_SIGNAL_0);
- continue;
- }
- }
+ do_cleanups (mthread_cleanups);
- /* The inferior is broken by a breakpoint or a signal. */
- break;
+ ret_ptid = inferior_ptid;
+ }
+ else
+ {
+ /* Single-thread record. */
+ if (record_resume_step)
+ {
+ /* This is a single step. */
+ ret_ptid = record_beneath_to_wait (record_beneath_to_wait_ops,
+ ptid, status, options);
}
+ else
+ {
+ /* This is not a single step. */
+ while (1)
+ {
+ if (record_thread_wait (ptid, status,
+ options, &ret_ptid))
+ break;
- return ret;
- }
+ if (record_resume_step)
+ break;
+
+ /* There is not a breakpoint, and gdb is not
+ stepping, therefore gdb will not stop.
+ Therefore we will not return to gdb.
+ Record the insn and resume. */
+ if (!do_record_message (TARGET_SIGNAL_0, 1))
+ {
+ ret_ptid = inferior_ptid;
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_0;
+ break;
+ }
+
+ record_beneath_to_resume (record_beneath_to_resume_ops,
+ record_resume_ptid, record_step,
+ TARGET_SIGNAL_0);
+ }
+ }
+ }
}
else
{
- struct regcache *regcache = get_current_regcache ();
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ /* Replay mode. */
+ struct regcache *regcache;
+ struct gdbarch *gdbarch;
int continue_flag = 1;
int first_record_end = 1;
- struct cleanup *old_cleanups = make_cleanup (record_wait_cleanups, 0);
+ struct cleanup *old_cleanups =
+ make_cleanup (record_wait_replay_cleanups, 0);
CORE_ADDR tmp_pc;
+ ptid_t old_inferior_ptid = inferior_ptid;
+
+ if (!ptid_equal (record_prev_ptid, null_ptid))
+ inferior_ptid = record_prev_ptid;
+ regcache = get_current_regcache ();
+ gdbarch = get_regcache_arch (regcache);
status->kind = TARGET_WAITKIND_STOPPED;
@@ -1129,8 +1561,6 @@ record_wait (struct target_ops *ops,
}
}
- record_get_sig = 0;
- signal (SIGINT, record_sig_handler);
/* If GDB is in terminal_inferior mode, it will not get the signal.
And in GDB replay mode, GDB doesn't need to be in terminal_inferior
mode, because inferior will not executed.
@@ -1161,7 +1591,7 @@ record_wait (struct target_ops *ops,
break;
}
- record_exec_insn (regcache, gdbarch, record_list);
+ record_exec_insn (®cache, &gdbarch, record_list);
if (record_list->type == record_end)
{
@@ -1184,12 +1614,13 @@ record_wait (struct target_ops *ops,
In EXEC_FORWARD mode, this is the record_end of current
instruction. */
/* step */
- if (record_resume_step)
+ if (record_resume_step
+ && ptid_equal (inferior_ptid, old_inferior_ptid))
{
if (record_debug > 1)
fprintf_unfiltered (gdb_stdlog,
"Process record: step.\n");
- continue_flag = 0;
+ continue_flag = 0;
}
/* check breakpoint */
@@ -1233,22 +1664,23 @@ record_wait (struct target_ops *ops,
}
while (continue_flag);
- signal (SIGINT, handle_sigint);
-
replay_out:
- if (record_get_sig)
- status->value.sig = TARGET_SIGNAL_INT;
- else if (record_list->u.end.sigval != TARGET_SIGNAL_0)
+ if (record_list->u.end.sigval != TARGET_SIGNAL_0)
/* FIXME: better way to check */
status->value.sig = record_list->u.end.sigval;
else
status->value.sig = TARGET_SIGNAL_TRAP;
+ ret_ptid = inferior_ptid;
discard_cleanups (old_cleanups);
}
+ if (record_get_sig)
+ status->value.sig = TARGET_SIGNAL_INT;
+
+ do_cleanups (signal_cleanups);
do_cleanups (set_cleanups);
- return inferior_ptid;
+ return ret_ptid;
}
/* "to_disconnect" method for process record target. */
@@ -1311,6 +1743,12 @@ record_registers_change (struct regcache
record_arch_list_head = NULL;
record_arch_list_tail = NULL;
+ if (!ptid_equal (record_prev_ptid, inferior_ptid))
+ {
+ record_arch_list_add_ptid (&record_prev_ptid);
+ record_prev_ptid = inferior_ptid;
+ }
+
if (regnum < 0)
{
int i;
@@ -1433,6 +1871,11 @@ record_xfer_partial (struct target_ops *
/* Record registers change to list as an instruction. */
record_arch_list_head = NULL;
record_arch_list_tail = NULL;
+ if (!ptid_equal (record_prev_ptid, inferior_ptid))
+ {
+ record_arch_list_add_ptid (&record_prev_ptid);
+ record_prev_ptid = inferior_ptid;
+ }
if (record_arch_list_add_mem (offset, len))
{
record_list_release (record_arch_list_tail);
@@ -2088,6 +2531,32 @@ record_restore (void)
rec->u.mem.len);
break;
+ case record_ptid: /* ptid */
+ rec = record_ptid_alloc ();
+
+ /* Get Process id. */
+ bfdcore_read (core_bfd, osec, &addr,
+ sizeof (addr), &bfd_offset);
+ rec->u.ptid.pid = (int) netorder64 (addr);
+
+ /* Get Lightweight process id. */
+ bfdcore_read (core_bfd, osec, &addr,
+ sizeof (addr), &bfd_offset);
+ rec->u.ptid.lwp = (long) netorder64 (addr);
+
+ /* Get Thread id. */
+ bfdcore_read (core_bfd, osec, &addr,
+ sizeof (addr), &bfd_offset);
+ rec->u.ptid.tid = (long) netorder64 (addr);
+
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "\
+ Reading ptid %s (1 + 8 + 8 + 8 bytes), offset == %s\n",
+ target_pid_to_str (record_list->u.ptid),
+ paddress (get_current_arch (),
+ bfd_offset));
+ break;
+
case record_end: /* end */
rec = record_end_alloc ();
record_insn_num ++;
@@ -2240,7 +2709,7 @@ cmd_record_save (char *args, int from_tt
if (record_list == &record_first)
break;
- record_exec_insn (regcache, gdbarch, record_list);
+ record_exec_insn (®cache, &gdbarch, record_list);
if (record_list->prev)
record_list = record_list->prev;
@@ -2261,6 +2730,9 @@ cmd_record_save (char *args, int from_tt
case record_mem:
save_size += 1 + 4 + 8 + record_list->u.mem.len;
break;
+ case record_ptid:
+ save_size += 1 + 8 + 8 + 8;
+ break;
}
/* Make the new bfd section. */
@@ -2347,6 +2819,25 @@ cmd_record_save (char *args, int from_tt
record_list->u.mem.len, &bfd_offset);
break;
+ case record_ptid: /* ptid */
+ if (record_debug)
+ fprintf_unfiltered (gdb_stdlog, "\
+ Writing ptid %s (1 plus 8 plus 8 plus 8 bytes)\n",
+ target_pid_to_str (record_list->u.ptid));
+
+ /* Write Process id. */
+ addr = netorder64 ((uint64_t) record_list->u.ptid.pid);
+ bfdcore_write (obfd, osec, &addr, sizeof (addr), &bfd_offset);
+
+ /* Write Lightweight process id. */
+ addr = netorder64 ((uint64_t) record_list->u.ptid.lwp);
+ bfdcore_write (obfd, osec, &addr, sizeof (addr), &bfd_offset);
+
+ /* Write Thread id. */
+ addr = netorder64 ((uint64_t) record_list->u.ptid.tid);
+ bfdcore_write (obfd, osec, &addr, sizeof (addr), &bfd_offset);
+ break;
+
case record_end:
if (record_debug)
fprintf_unfiltered (gdb_stdlog, "\
@@ -2367,7 +2858,7 @@ cmd_record_save (char *args, int from_tt
}
/* Execute entry. */
- record_exec_insn (regcache, gdbarch, record_list);
+ record_exec_insn (®cache, &gdbarch, record_list);
if (record_list->next)
record_list = record_list->next;
@@ -2382,7 +2873,7 @@ cmd_record_save (char *args, int from_tt
if (record_list == cur_record_list)
break;
- record_exec_insn (regcache, gdbarch, record_list);
+ record_exec_insn (®cache, &gdbarch, record_list);
if (record_list->prev)
record_list = record_list->prev;
--- a/record.h
+++ b/record.h
@@ -23,6 +23,7 @@
#define RECORD_IS_USED (current_target.to_stratum == record_stratum)
extern int record_debug;
+extern int record_step;
extern int record_arch_list_add_reg (struct regcache *regcache, int num);
extern int record_arch_list_add_mem (CORE_ADDR addr, int len);
--- a/thread.c
+++ b/thread.c
@@ -63,15 +63,6 @@ static void thread_apply_command (char *
static void restore_current_thread (ptid_t);
static void prune_threads (void);
-/* Frontend view of the thread state. Possible extensions: stepping,
- finishing, until(ling),... */
-enum thread_state
-{
- THREAD_STOPPED,
- THREAD_RUNNING,
- THREAD_EXITED,
-};
-
struct thread_info*
inferior_thread (void)
{
next prev parent reply other threads:[~2009-11-12 8:26 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-11-02 16:45 Hui Zhu
2009-11-02 18:14 ` Michael Snyder
2009-11-09 18:00 ` Tom Tromey
2009-11-12 8:26 ` Hui Zhu [this message]
2009-11-13 9:27 ` Hui Zhu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=daef60380911120025g3d20d304qb82d2519f2ceee6e@mail.gmail.com \
--to=teawater@gmail.com \
--cc=gdb-patches@sourceware.org \
--cc=msnyder@vmware.com \
--cc=tromey@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox