libipt, block: add end-on-call block decoder option

Add a new block decoder option to end a block after a call instruction.  This is
useful if you are interested in calls and rets so you only ever need to look at
the last intruction of a block - or the first, depending on your interest.

Change-Id: I7f27e32a11492ea02abad4d032246d97acce33a0
Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
diff --git a/libipt/include/intel-pt.h b/libipt/include/intel-pt.h
index 52c0ce1..7ccfaf9 100644
--- a/libipt/include/intel-pt.h
+++ b/libipt/include/intel-pt.h
@@ -584,6 +584,12 @@
 struct pt_conf_flags {
 	/** The decoder variant. */
 	union {
+		/** Flags for the block decoder. */
+		struct {
+			/** End a block after a call instruction. */
+			uint32_t end_on_call:1;
+		} block;
+
 		/* Reserve a few bytes for future extensions. */
 		uint32_t reserved[4];
 	} variant;
diff --git a/libipt/src/pt_block_decoder.c b/libipt/src/pt_block_decoder.c
index 826e7b0..576109d 100644
--- a/libipt/src/pt_block_decoder.c
+++ b/libipt/src/pt_block_decoder.c
@@ -1207,7 +1207,7 @@
 {
 	int status;
 
-	if (!decoder || !predicate)
+	if (!decoder || !insn || !predicate)
 		return -pte_internal;
 
 	for (;;) {
@@ -1226,6 +1226,15 @@
 		status = pt_insn_next_ip(&decoder->ip, insn, iext);
 		if (status < 0)
 			return status;
+
+		/* End the block if the user asked us to.
+		 *
+		 * We only need to take care about direct near calls.  Indirect
+		 * and far calls require trace and will naturally end a block.
+		 */
+		if (decoder->flags.variant.block.end_on_call &&
+		    (insn->iclass == ptic_call))
+			return 0;
 	}
 }
 
@@ -1254,7 +1263,7 @@
 {
 	int status;
 
-	if (!decoder)
+	if (!decoder || !insn)
 		return -pte_internal;
 
 	for (;;) {
@@ -1272,6 +1281,15 @@
 		status = pt_insn_next_ip(&decoder->ip, insn, iext);
 		if (status < 0)
 			return status;
+
+		/* End the block if the user asked us to.
+		 *
+		 * We only need to take care about direct near calls.  Indirect
+		 * and far calls require trace and will naturally end a block.
+		 */
+		if (decoder->flags.variant.block.end_on_call &&
+		    (insn->iclass == ptic_call))
+			return 0;
 	}
 }
 
@@ -1978,7 +1996,8 @@
 	 *     displacement.
 	 *
 	 *     We could proceed after a near direct call but we migh as well
-	 *     postpone it to the next iteration.
+	 *     postpone it to the next iteration.  Make sure to end the block if
+	 *     @decoder->flags.variant.block.end_on_call is set, though.
 	 *
 	 *   - if we switched sections
 	 *
@@ -2335,6 +2354,15 @@
 			return pt_blk_proceed_with_trace(decoder, &insn, &iext);
 		}
 
+		/* End the block if the user asked us to.
+		 *
+		 * We only need to take care about direct near calls.  Indirect
+		 * and far calls require trace and will naturally end a block.
+		 */
+		if (decoder->flags.variant.block.end_on_call &&
+		    (insn.iclass == ptic_call))
+			break;
+
 		/* If we can proceed without trace and we stay in @section we
 		 * may proceed further.
 		 *