/* -*- Mode: C++; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */

#ifndef RR_FAST_FORWARD_H_
#define RR_FAST_FORWARD_H_

#include <vector>

#include "Task.h"

namespace rr {

class Registers;

struct FastForwardStatus {
  FastForwardStatus() : did_fast_forward(false), incomplete_fast_forward(false) {}
  FastForwardStatus(const FastForwardStatus& other) = default;
  FastForwardStatus& operator=(const FastForwardStatus& other) = default;
  FastForwardStatus& operator|=(const FastForwardStatus& other) {
    did_fast_forward |= other.did_fast_forward;
    incomplete_fast_forward |= other.incomplete_fast_forward;
    return *this;
  }
  bool did_fast_forward;
  bool incomplete_fast_forward;
};

/**
 * Perform one or more synchronous singlesteps of |t|. Usually just does
 * one singlestep, except when a singlestep leaves the IP unchanged (i.e. a
 * single instruction represents a loop, such as an x86 REP-prefixed string
 * instruction).
 *
 * |how| must be either RESUME_SINGLESTEP or RESUME_SYSEMU_SINGLESTEP.
 *
 * We always perform at least one singlestep. We stop after a singlestep if
 * one of the following is true, or will be true after one more singlestep:
 * -- Any breakpoint or watchpoint has been triggered
 * -- IP has advanced to the next instruction
 * -- One of the register states in |states| (a null-terminated list)
 * has been reached.
 *
 * Spurious returns after any singlestep are also allowed.
 *
 * This will not add more than one tick to t->tick_count().
 *
 * Returns true if we did a fast-forward, false if we just did one regular
 * singlestep.
 */
FastForwardStatus fast_forward_through_instruction(
    Task* t, ResumeRequest how, const std::vector<const Registers*>& states);

/**
 * Return true if the instruction at t->ip(), or the instruction immediately
 * before t->ip(), could be a REP-prefixed string instruction. It's OK to
 * return true if it's not really a string instruction (though for performance
 * reasons, this should be rare).
 */
bool maybe_at_or_after_x86_string_instruction(Task* t);

/* Return true if the instruction at t->ip() is a string instruction */
bool at_x86_string_instruction(Task* t);

} // namespace rr

#endif // RR_FAST_FORWARD_H_
