if (!target_has_execution)
error (_("The program is not being run."));
- if (non_stop)
- error (_("Record btrace can't debug inferior in non-stop mode."));
-
gdb_assert (record_btrace_thread_observer == NULL);
disable_chain = make_cleanup (null_cleanup, NULL);
/* The to_record_is_replaying method of target record-btrace. */
static int
-record_btrace_is_replaying (struct target_ops *self)
+record_btrace_is_replaying (struct target_ops *self, ptid_t ptid)
{
struct thread_info *tp;
ALL_NON_EXITED_THREADS (tp)
- if (btrace_is_replaying (tp))
+ if (ptid_match (tp->ptid, ptid) && btrace_is_replaying (tp))
return 1;
return 0;
/* Filter out requests that don't make sense during replay. */
if (replay_memory_access == replay_memory_access_read_only
&& !record_btrace_generating_corefile
- && record_btrace_is_replaying (ops))
+ && record_btrace_is_replaying (ops, inferior_ptid))
{
switch (object)
{
{
struct target_ops *t;
- if (!record_btrace_generating_corefile && record_btrace_is_replaying (ops))
- error (_("This record target does not allow writing registers."));
+ if (!record_btrace_generating_corefile
+ && record_btrace_is_replaying (ops, inferior_ptid))
+ error (_("Cannot write registers while replaying."));
gdb_assert (may_write_registers != 0);
{
struct target_ops *t;
- if (!record_btrace_generating_corefile && record_btrace_is_replaying (ops))
+ if (!record_btrace_generating_corefile
+ && record_btrace_is_replaying (ops, inferior_ptid))
return;
t = ops->beneath;
btinfo->flags |= flag;
}
+/* Get the current frame for TP. */
+
+static struct frame_info *
+get_thread_current_frame (struct thread_info *tp)
+{
+ struct frame_info *frame;
+ ptid_t old_inferior_ptid;
+ int executing;
+
+ /* Set INFERIOR_PTID, which is implicitly used by get_current_frame. */
+ old_inferior_ptid = inferior_ptid;
+ inferior_ptid = tp->ptid;
+
+ /* Clear the executing flag to allow changes to the current frame.
+ We are not actually running, yet. We just started a reverse execution
+ command or a record goto command.
+ For the latter, EXECUTING is false and this has no effect.
+ For the former, EXECUTING is true and we're in to_wait, about to
+ move the thread. Since we need to recompute the stack, we temporarily
+ set EXECUTING to flase. */
+ executing = is_executing (inferior_ptid);
+ set_executing (inferior_ptid, 0);
+
+ frame = NULL;
+ TRY
+ {
+ frame = get_current_frame ();
+ }
+ CATCH (except, RETURN_MASK_ALL)
+ {
+ /* Restore the previous execution state. */
+ set_executing (inferior_ptid, executing);
+
+ /* Restore the previous inferior_ptid. */
+ inferior_ptid = old_inferior_ptid;
+
+ throw_exception (except);
+ }
+ END_CATCH
+
+ /* Restore the previous execution state. */
+ set_executing (inferior_ptid, executing);
+
+ /* Restore the previous inferior_ptid. */
+ inferior_ptid = old_inferior_ptid;
+
+ return frame;
+}
+
/* Start replaying a thread. */
static struct btrace_insn_iterator *
{
struct btrace_insn_iterator *replay;
struct btrace_thread_info *btinfo;
- int executing;
btinfo = &tp->btrace;
replay = NULL;
if (btinfo->begin == NULL)
return NULL;
- /* Clear the executing flag to allow changes to the current frame.
- We are not actually running, yet. We just started a reverse execution
- command or a record goto command.
- For the latter, EXECUTING is false and this has no effect.
- For the former, EXECUTING is true and we're in to_wait, about to
- move the thread. Since we need to recompute the stack, we temporarily
- set EXECUTING to flase. */
- executing = is_executing (tp->ptid);
- set_executing (tp->ptid, 0);
-
/* GDB stores the current frame_id when stepping in order to detects steps
into subroutines.
Since frames are computed differently when we're replaying, we need to
int upd_step_frame_id, upd_step_stack_frame_id;
/* The current frame without replaying - computed via normal unwind. */
- frame = get_current_frame ();
+ frame = get_thread_current_frame (tp);
frame_id = get_frame_id (frame);
/* Check if we need to update any stepping-related frame id's. */
registers_changed_ptid (tp->ptid);
/* The current frame with replaying - computed via btrace unwind. */
- frame = get_current_frame ();
+ frame = get_thread_current_frame (tp);
frame_id = get_frame_id (frame);
/* Replace stepping related frames where necessary. */
}
CATCH (except, RETURN_MASK_ALL)
{
- /* Restore the previous execution state. */
- set_executing (tp->ptid, executing);
-
xfree (btinfo->replay);
btinfo->replay = NULL;
}
END_CATCH
- /* Restore the previous execution state. */
- set_executing (tp->ptid, executing);
-
return replay;
}
/* ...and we stop replaying other threads if the thread to resume is not
replaying. */
if (!btrace_is_replaying (tp) && execution_direction != EXEC_REVERSE)
- ALL_NON_EXITED_THREADS (tp)
- record_btrace_stop_replaying (tp);
+ target_record_stop_replaying ();
}
/* As long as we're not replaying, just forward the request.
For non-stop targets this means that no thread is replaying. In order to
make progress, we may need to explicitly move replaying threads to the end
of their execution history. */
- if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
+ if ((execution_direction != EXEC_REVERSE)
+ && !record_btrace_is_replaying (ops, minus_one_ptid))
{
ops = ops->beneath;
return ops->to_resume (ops, orig_ptid, step, signal);
typedef struct thread_info * tp_t;
DEF_VEC_P (tp_t);
+/* Announce further events if necessary. */
+
+static void
+record_btrace_maybe_mark_async_event (const VEC (tp_t) *moving,
+ const VEC (tp_t) *no_history)
+{
+ int more_moving, more_no_history;
+
+ more_moving = !VEC_empty (tp_t, moving);
+ more_no_history = !VEC_empty (tp_t, no_history);
+
+ if (!more_moving && !more_no_history)
+ return;
+
+ if (more_moving)
+ DEBUG ("movers pending");
+
+ if (more_no_history)
+ DEBUG ("no-history pending");
+
+ mark_async_event_handler (record_btrace_async_inferior_event_handler);
+}
+
/* The to_wait method of target record-btrace. */
static ptid_t
DEBUG ("wait %s (0x%x)", target_pid_to_str (ptid), options);
/* As long as we're not replaying, just forward the request. */
- if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
+ if ((execution_direction != EXEC_REVERSE)
+ && !record_btrace_is_replaying (ops, minus_one_ptid))
{
ops = ops->beneath;
return ops->to_wait (ops, ptid, status, options);
ALL_NON_EXITED_THREADS (tp)
record_btrace_cancel_resume (tp);
+ /* In async mode, we need to announce further events. */
+ if (target_is_async_p ())
+ record_btrace_maybe_mark_async_event (moving, no_history);
+
/* Start record histories anew from the current position. */
record_btrace_clear_histories (&eventing->btrace);
DEBUG ("stop %s", target_pid_to_str (ptid));
/* As long as we're not replaying, just forward the request. */
- if (!record_btrace_is_replaying (ops) && execution_direction != EXEC_REVERSE)
+ if ((execution_direction != EXEC_REVERSE)
+ && !record_btrace_is_replaying (ops, minus_one_ptid))
{
ops = ops->beneath;
ops->to_stop (ops, ptid);
static int
record_btrace_stopped_by_sw_breakpoint (struct target_ops *ops)
{
- if (record_btrace_is_replaying (ops))
+ if (record_btrace_is_replaying (ops, minus_one_ptid))
{
struct thread_info *tp = inferior_thread ();
static int
record_btrace_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
{
- if (record_btrace_is_replaying (ops))
+ if (record_btrace_is_replaying (ops, minus_one_ptid))
return 1;
return ops->beneath->to_supports_stopped_by_sw_breakpoint (ops->beneath);
static int
record_btrace_stopped_by_hw_breakpoint (struct target_ops *ops)
{
- if (record_btrace_is_replaying (ops))
+ if (record_btrace_is_replaying (ops, minus_one_ptid))
{
struct thread_info *tp = inferior_thread ();
static int
record_btrace_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
{
- if (record_btrace_is_replaying (ops))
+ if (record_btrace_is_replaying (ops, minus_one_ptid))
return 1;
return ops->beneath->to_supports_stopped_by_hw_breakpoint (ops->beneath);
record_btrace_update_thread_list (struct target_ops *ops)
{
/* We don't add or remove threads during replay. */
- if (record_btrace_is_replaying (ops))
+ if (record_btrace_is_replaying (ops, minus_one_ptid))
return;
/* Forward the request. */
record_btrace_thread_alive (struct target_ops *ops, ptid_t ptid)
{
/* We don't add or remove threads during replay. */
- if (record_btrace_is_replaying (ops))
+ if (record_btrace_is_replaying (ops, minus_one_ptid))
return find_thread_ptid (ptid) != NULL;
/* Forward the request. */
record_btrace_set_replay (tp, &it);
}
+/* The to_record_stop_replaying method of target record-btrace. */
+
+static void
+record_btrace_stop_replaying_all (struct target_ops *self)
+{
+ struct thread_info *tp;
+
+ ALL_NON_EXITED_THREADS (tp)
+ record_btrace_stop_replaying (tp);
+}
+
/* The to_execution_direction target method. */
static enum exec_direction_kind
ops->to_call_history_from = record_btrace_call_history_from;
ops->to_call_history_range = record_btrace_call_history_range;
ops->to_record_is_replaying = record_btrace_is_replaying;
+ ops->to_record_stop_replaying = record_btrace_stop_replaying_all;
ops->to_xfer_partial = record_btrace_xfer_partial;
ops->to_remove_breakpoint = record_btrace_remove_breakpoint;
ops->to_insert_breakpoint = record_btrace_insert_breakpoint;