libipt, insn: add pt_insn_range_is_contiguous()

Add a function to check for a contiguous range of instructions, in the sense
that we can reach the last instruction in the range from the first without using
trace.

The instructions are given by their IPs.

Change-Id: Ia4adf35803c67471811eea2aefd7ff67efa23aa0
Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
diff --git a/libipt/internal/include/pt_insn.h b/libipt/internal/include/pt_insn.h
index 8b8a214..802590c 100644
--- a/libipt/internal/include/pt_insn.h
+++ b/libipt/internal/include/pt_insn.h
@@ -31,10 +31,9 @@
 
 #include <inttypes.h>
 
-struct pt_insn;
+#include "intel-pt.h"
+
 struct pt_insn_ext;
-struct pt_asid;
-struct pt_image;
 
 
 /* A finer-grain classification of instructions used internally. */
@@ -187,4 +186,18 @@
 extern int pt_insn_decode(struct pt_insn *insn, struct pt_insn_ext *iext,
 			  struct pt_image *image, const struct pt_asid *asid);
 
+/* Determine if a range of instructions is contiguous.
+ *
+ * Try to proceed from IP @begin to IP @end in @asid without using trace.
+ *
+ * Returns a positive integer if we reach @end from @begin.
+ * Returns zero if we couldn't reach @end within @nsteps steps.
+ * Returns a negative error code otherwise.
+ */
+extern int pt_insn_range_is_contiguous(uint64_t begin, uint64_t end,
+				       enum pt_exec_mode mode,
+				       struct pt_image *image,
+				       const struct pt_asid *asid,
+				       size_t nsteps);
+
 #endif /* PT_INSN_H */
diff --git a/libipt/src/pt_insn.c b/libipt/src/pt_insn.c
index 4de5e47..7bba5c3 100644
--- a/libipt/src/pt_insn.c
+++ b/libipt/src/pt_insn.c
@@ -317,3 +317,33 @@
 
 	return errcode;
 }
+
+int pt_insn_range_is_contiguous(uint64_t begin, uint64_t end,
+				enum pt_exec_mode mode, struct pt_image *image,
+				const struct pt_asid *asid, size_t steps)
+{
+	struct pt_insn_ext iext;
+	struct pt_insn insn;
+
+	memset(&insn, 0, sizeof(insn));
+
+	insn.mode = mode;
+	insn.ip = begin;
+
+	while (insn.ip != end) {
+		int errcode;
+
+		if (!steps--)
+			return 0;
+
+		errcode = pt_insn_decode(&insn, &iext, image, asid);
+		if (errcode < 0)
+			return errcode;
+
+		errcode = pt_insn_next_ip(&insn.ip, &insn, &iext);
+		if (errcode < 0)
+			return errcode;
+	}
+
+	return 1;
+}