{
record_full_end = 0,
record_full_reg,
- record_full_mem
+ record_full_mem,
+ record_full_ptid,
};
/* This is the data structure that makes up the execution log.
struct record_full_mem_entry mem;
/* end */
struct record_full_end_entry end;
+
+ ptid_t ptid;
} u;
};
return rec;
}
+/* Allocate a record_full_ptid record entry. */
+
+static inline struct record_full_entry *
+record_full_ptid_alloc (ptid_t ptid)
+{
+ struct record_full_entry *rec;
+
+ rec = XCNEW (struct record_full_entry);
+ rec->type = record_full_ptid;
+ rec->u.ptid = ptid;
+
+ return rec;
+}
+
/* Free a record_full_mem record entry. */
static inline void
xfree (rec);
}
+static inline void
+record_full_ptid_release (struct record_full_entry *rec)
+{
+ xfree (rec);
+}
+
/* Free one record entry, any type.
Return entry->type, in case caller wants to know. */
case record_full_end:
record_full_end_release (rec);
break;
+ case record_full_ptid:
+ record_full_ptid_release (rec);
+ break;
+ default:
+ gdb_assert_not_reached ("unhandled record_full_entry type");
}
return type;
}
else
return rec->u.reg.u.buf;
case record_full_end:
+ case record_full_ptid:
default:
gdb_assert_not_reached ("unexpected record_full_entry type");
return NULL;
return 0;
}
+/* Add a PTID entry to the history, marking that the replay should
+ switch threads. */
+
+static bool
+record_full_arch_list_add_ptid (ptid_t ptid)
+{
+ struct record_full_entry *rec;
+
+ if (record_debug > 1)
+ gdb_printf (gdb_stdlog,
+ "Process record: add ptid to "
+ "record list.\n");
+
+ rec = record_full_ptid_alloc (ptid);
+ record_full_arch_list_add (rec);
+ return true;
+}
+
/* Add a record_full_end type struct record_full_entry to
record_full_arch_list. */
only can step), GDB will call this function to record the values to
record_full_list. This function will call gdbarch_process_record to
record the running message of inferior and set them to
- record_full_arch_list, and add it to record_full_list. */
+ record_full_arch_list, and add it to record_full_list.
+ PTID contains the PID and TID of the instruction being recorded. */
static void
-record_full_message (struct regcache *regcache, enum gdb_signal signal)
+record_full_message (struct regcache *regcache, enum gdb_signal signal,
+ ptid_t ptid)
{
int ret;
struct gdbarch *gdbarch = regcache->arch ();
/* Check record_full_insn_num. */
record_full_check_insn_num ();
+ /* If there is more than one thread, the history should know which
+ thread the current instruction belongs to. */
+ if (thread_count (nullptr) > 1)
+ record_full_arch_list_add_ptid (ptid);
+
/* If gdb sends a signal value to target_resume,
save it in the 'end' field of the previous instruction.
static bool
record_full_message_wrapper_safe (struct regcache *regcache,
- enum gdb_signal signal)
+ enum gdb_signal signal, ptid_t ptid)
{
try
{
- record_full_message (regcache, signal);
+ record_full_message (regcache, signal, ptid);
}
catch (const gdb_exception_error &ex)
{
struct regcache *regcache = get_thread_regcache (inferior_thread ());
struct gdbarch *gdbarch = regcache->arch ();
- record_full_message (regcache, signal);
+ record_full_message (regcache, signal, ptid);
if (!step)
{
{
if (record_full_resume_step)
{
- /* This is a single step. */
return ops->beneath ()->wait (ptid, status, options);
}
else
int step = 1;
if (!record_full_message_wrapper_safe (regcache,
- GDB_SIGNAL_0))
+ GDB_SIGNAL_0,
+ ptid))
{
status->set_stopped (GDB_SIGNAL_0);
break;
}
else
{
+ bool multi_thread = (thread_count (nullptr) > 1);
switch_to_thread (current_inferior ()->process_target (),
record_full_resume_ptid);
regcache *regcache = get_thread_regcache (inferior_thread ());
break;
}
+ if (multi_thread)
+ {
+ if (execution_direction == EXEC_REVERSE)
+ {
+ record_full_entry *pid_entry = record_full_list;
+ while (pid_entry->type != record_full_end
+ && pid_entry->type != record_full_ptid
+ && pid_entry->prev != nullptr)
+ pid_entry = pid_entry->prev;
+ /* If we couldn't find the ptid,
+ there's no need to change threads. */
+ if (pid_entry->type == record_full_ptid)
+ {
+ switch_to_thread
+ (current_inferior ()->process_target (),
+ pid_entry->u.ptid);
+ regcache = get_thread_regcache (inferior_thread ());
+ }
+ }
+ else
+ {
+ record_full_entry *pid_entry = record_full_list;
+ while (pid_entry->type != record_full_end
+ && pid_entry->type != record_full_ptid
+ && pid_entry->next != nullptr)
+ pid_entry = pid_entry->next;
+ /* If we couldn't find the ptid,
+ there's no need to change threads. */
+ if (pid_entry->type == record_full_ptid)
+ {
+ switch_to_thread
+ (current_inferior ()->process_target (),
+ pid_entry->u.ptid);
+ regcache = get_thread_regcache (inferior_thread ());
+ }
+ }
+ }
+
record_full_exec_insn (regcache, gdbarch, record_full_list);
if (record_full_list->type == record_full_end)
gdb_printf ("\n");
break;
}
+ case record_full_ptid:
+ gdb_printf ("Instruction referencing thread %s\n",
+ to_print->u.ptid.to_string ().c_str ());
+ break;
+ default:
+ gdb_assert_not_reached ("Unhandled record type");
}
to_print = to_print->next;
}