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.
*