static void
btrace_insn_history (struct ui_out *uiout,
		     const struct btrace_insn_iterator *begin,
		     const struct btrace_insn_iterator *end, int flags)
{
  struct gdbarch *gdbarch;
  struct btrace_insn_iterator it;

  DEBUG ("itrace (0x%x): [%u; %u)", flags, btrace_insn_number (begin),
	 btrace_insn_number (end));

  gdbarch = target_gdbarch ();

  for (it = *begin; btrace_insn_cmp (&it, end) != 0; btrace_insn_next (&it, 1))
    {
      const struct btrace_insn *insn;

      insn = btrace_insn_get (&it);

      /* Print the instruction index.  */
      ui_out_field_uint (uiout, "index", btrace_insn_number (&it));
      ui_out_text (uiout, "\t");

      /* Disassembly with '/m' flag may not produce the expected result.
	 See PR gdb/11833.  */
      gdb_disassembly (gdbarch, uiout, NULL, flags, 1, insn->pc, insn->pc + 1);
    }
}
static void
record_btrace_fetch_registers (struct target_ops *ops,
			       struct regcache *regcache, int regno)
{
  struct btrace_insn_iterator *replay;
  struct thread_info *tp;

  tp = find_thread_ptid (inferior_ptid);
  gdb_assert (tp != NULL);

  replay = tp->btrace.replay;
  if (replay != NULL)
    {
      const struct btrace_insn *insn;
      struct gdbarch *gdbarch;
      int pcreg;

      gdbarch = get_regcache_arch (regcache);
      pcreg = gdbarch_pc_regnum (gdbarch);
      if (pcreg < 0)
	return;

      /* We can only provide the PC register.  */
      if (regno >= 0 && regno != pcreg)
	return;

      insn = btrace_insn_get (replay);
      gdb_assert (insn != NULL);

      regcache_raw_supply (regcache, regno, &insn->pc);
    }
  else
    {
      struct target_ops *t;

      for (t = ops->beneath; t != NULL; t = t->beneath)
	if (t->to_fetch_registers != NULL)
	  {
	    t->to_fetch_registers (t, regcache, regno);
	    break;
	  }
    }
}
static const btrace_insn *
btrace_insn_from_recpy_insn (const PyObject * const pyobject)
{
  const btrace_insn *insn;
  const recpy_element_object *obj;
  thread_info *tinfo;
  btrace_insn_iterator iter;

  if (Py_TYPE (pyobject) != &recpy_insn_type)
    {
      PyErr_Format (gdbpy_gdb_error, _("Must be gdb.RecordInstruction"));
      return NULL;
    }

  obj = (const recpy_element_object *) pyobject;
  tinfo = obj->thread;

  if (tinfo == NULL || btrace_is_empty (tinfo))
    {
      PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
      return NULL;
    }

  if (btrace_find_insn_by_number (&iter, &tinfo->btrace, obj->number) == 0)
    {
      PyErr_Format (gdbpy_gdb_error, _("No such instruction."));
      return NULL;
    }

  insn = btrace_insn_get (&iter);
  if (insn == NULL)
    {
      PyErr_Format (gdbpy_gdb_error, _("Not a valid instruction."));
      return NULL;
    }

  return insn;
}
static struct target_waitstatus
record_btrace_step_thread (struct thread_info *tp)
{
  struct btrace_insn_iterator *replay, end;
  struct btrace_thread_info *btinfo;
  struct address_space *aspace;
  struct inferior *inf;
  enum btrace_thread_flag flags;
  unsigned int steps;

  btinfo = &tp->btrace;
  replay = btinfo->replay;

  flags = btinfo->flags & BTHR_MOVE;
  btinfo->flags &= ~BTHR_MOVE;

  DEBUG ("stepping %d (%s): %u", tp->num, target_pid_to_str (tp->ptid), flags);

  switch (flags)
    {
    default:
      internal_error (__FILE__, __LINE__, _("invalid stepping type."));

    case BTHR_STEP:
      /* We're done if we're not replaying.  */
      if (replay == NULL)
	return btrace_step_no_history ();

      /* We are always able to step at least once.  */
      steps = btrace_insn_next (replay, 1);
      gdb_assert (steps == 1);

      /* Determine the end of the instruction trace.  */
      btrace_insn_end (&end, btinfo);

      /* We stop replaying if we reached the end of the trace.  */
      if (btrace_insn_cmp (replay, &end) == 0)
	record_btrace_stop_replaying (tp);

      return btrace_step_stopped ();

    case BTHR_RSTEP:
      /* Start replaying if we're not already doing so.  */
      if (replay == NULL)
	replay = record_btrace_start_replaying (tp);

      /* If we can't step any further, we reached the end of the history.  */
      steps = btrace_insn_prev (replay, 1);
      if (steps == 0)
	return btrace_step_no_history ();

      return btrace_step_stopped ();

    case BTHR_CONT:
      /* We're done if we're not replaying.  */
      if (replay == NULL)
	return btrace_step_no_history ();

      inf = find_inferior_pid (ptid_get_pid (tp->ptid));
      aspace = inf->aspace;

      /* Determine the end of the instruction trace.  */
      btrace_insn_end (&end, btinfo);

      for (;;)
	{
	  const struct btrace_insn *insn;

	  /* We are always able to step at least once.  */
	  steps = btrace_insn_next (replay, 1);
	  gdb_assert (steps == 1);

	  /* We stop replaying if we reached the end of the trace.  */
	  if (btrace_insn_cmp (replay, &end) == 0)
	    {
	      record_btrace_stop_replaying (tp);
	      return btrace_step_no_history ();
	    }

	  insn = btrace_insn_get (replay);
	  gdb_assert (insn);

	  DEBUG ("stepping %d (%s) ... %s", tp->num,
		 target_pid_to_str (tp->ptid),
		 core_addr_to_string_nz (insn->pc));

	  if (breakpoint_here_p (aspace, insn->pc))
	    return btrace_step_stopped ();
	}

    case BTHR_RCONT:
      /* Start replaying if we're not already doing so.  */
      if (replay == NULL)
	replay = record_btrace_start_replaying (tp);

      inf = find_inferior_pid (ptid_get_pid (tp->ptid));
      aspace = inf->aspace;

      for (;;)
	{
	  const struct btrace_insn *insn;

	  /* If we can't step any further, we're done.  */
	  steps = btrace_insn_prev (replay, 1);
	  if (steps == 0)
	    return btrace_step_no_history ();

	  insn = btrace_insn_get (replay);
	  gdb_assert (insn);

	  DEBUG ("reverse-stepping %d (%s) ... %s", tp->num,
		 target_pid_to_str (tp->ptid),
		 core_addr_to_string_nz (insn->pc));

	  if (breakpoint_here_p (aspace, insn->pc))
	    return btrace_step_stopped ();
	}
    }
}