libipt, ild, insn: store displacement in pt_insn_ext

Instead of storing the branch target in struct pt_insn_ext, we store the branch
displacement.

Change-Id: Ie93d74c045f34238592e2ae01f62f073e597c84c
Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
diff --git a/libipt/internal/include/pt_ild.h b/libipt/internal/include/pt_ild.h
index 9dc7374..e25d3c2 100644
--- a/libipt/internal/include/pt_ild.h
+++ b/libipt/internal/include/pt_ild.h
@@ -45,7 +45,6 @@
 
 struct pt_ild {
 	/* inputs */
-	uint64_t runtime_address;
 	uint8_t const *itext;
 	uint8_t max_bytes;	/*1..15 bytes  */
 	enum pt_exec_mode mode;
diff --git a/libipt/internal/include/pt_insn.h b/libipt/internal/include/pt_insn.h
index e91d124..b7f5e64 100644
--- a/libipt/internal/include/pt_insn.h
+++ b/libipt/internal/include/pt_insn.h
@@ -91,11 +91,14 @@
 	union {
 		/* For branch instructions. */
 		struct {
-			/* The target address.
+			/* The branch displacement.
 			 *
 			 * This is only valid for direct calls/jumps.
+			 *
+			 * The displacement is applied to the address of the
+			 * instruction following the branch.
 			 */
-			uint64_t target;
+			int32_t displacement;
 
 			/* A flag saying whether the branch is direct.
 			 *
diff --git a/libipt/src/pt_ild.c b/libipt/src/pt_ild.c
index 8886eb1..fc551a4 100644
--- a/libipt/src/pt_ild.c
+++ b/libipt/src/pt_ild.c
@@ -859,48 +859,28 @@
 	return prefix_decode(ild, 0, 0);
 }
 
-static inline int64_t sign_extend_bq(int8_t x)
-{
-	return x;
-}
-
-static inline int64_t sign_extend_wq(int16_t x)
-{
-	return x;
-}
-
-static inline int64_t sign_extend_dq(int32_t x)
-{
-	return x;
-}
-
 static int set_branch_target(struct pt_insn_ext *iext, const struct pt_ild *ild)
 {
-	int64_t npc;
-	uint64_t sign_extended_disp = 0;
-
 	if (!iext || !ild)
 		return -pte_internal;
 
-	if (ild->disp_bytes == 1)
-		sign_extended_disp =
-		    sign_extend_bq(get_byte(ild, ild->disp_pos));
-	else if (ild->disp_bytes == 2) {
+	iext->variant.branch.is_direct = 1;
+
+	if (ild->disp_bytes == 1) {
+		int8_t *b = (int8_t *) (get_byte_ptr(ild, ild->disp_pos));
+
+		iext->variant.branch.displacement = *b;
+	} else if (ild->disp_bytes == 2) {
 		int16_t *w = (int16_t *) (get_byte_ptr(ild, ild->disp_pos));
 
-		sign_extended_disp = sign_extend_wq(*w);
+		iext->variant.branch.displacement = *w;
 	} else if (ild->disp_bytes == 4) {
 		int32_t *d = (int32_t *) (get_byte_ptr(ild, ild->disp_pos));
 
-		sign_extended_disp = sign_extend_dq(*d);
+		iext->variant.branch.displacement = *d;
 	} else
 		return -pte_bad_insn;
 
-	npc = (int64_t) (ild->runtime_address + ild->length);
-
-	iext->variant.branch.is_direct = 1;
-	iext->variant.branch.target = (uint64_t) (npc + sign_extended_disp);
-
 	return 0;
 }
 
@@ -1215,7 +1195,6 @@
 	ild.mode = insn->mode;
 	ild.itext = insn->raw;
 	ild.max_bytes = insn->size;
-	ild.runtime_address = insn->ip;
 
 	errcode = pt_instruction_length_decode(&ild);
 	if (errcode < 0)
diff --git a/libipt/src/pt_insn.c b/libipt/src/pt_insn.c
index 72b5c9c..f095869 100644
--- a/libipt/src/pt_insn.c
+++ b/libipt/src/pt_insn.c
@@ -149,24 +149,25 @@
 	}
 }
 
-int pt_insn_next_ip(uint64_t *ip, const struct pt_insn *insn,
+int pt_insn_next_ip(uint64_t *pip, const struct pt_insn *insn,
 		    const struct pt_insn_ext *iext)
 {
+	uint64_t ip;
+
 	if (!insn || !iext)
 		return -pte_internal;
 
+	ip = insn->ip + insn->size;
+
 	switch (insn->iclass) {
 	case ptic_other:
-		if (ip)
-			*ip = insn->ip + insn->size;
-		return 0;
+		break;
 
 	case ptic_call:
 	case ptic_jump:
 		if (iext->variant.branch.is_direct) {
-			if (ip)
-				*ip = iext->variant.branch.target;
-			return 0;
+			ip += iext->variant.branch.displacement;
+			break;
 		}
 
 		/* Fall through. */
@@ -176,4 +177,9 @@
 	case ptic_error:
 		return -pte_bad_insn;
 	}
+
+	if (pip)
+		*pip = ip;
+
+	return 0;
 }
diff --git a/libipt/src/pt_insn_decoder.c b/libipt/src/pt_insn_decoder.c
index cbe8edc..3274a67 100644
--- a/libipt/src/pt_insn_decoder.c
+++ b/libipt/src/pt_insn_decoder.c
@@ -883,10 +883,16 @@
 				 * may ignore direct branches that go to a
 				 * different IP.
 				 */
-				if (iext->variant.branch.is_direct &&
-				    (iext->variant.branch.target !=
-				     ev->variant.disabled.ip))
-					break;
+				if (iext->variant.branch.is_direct) {
+					uint64_t ip;
+
+					ip = insn->ip;
+					ip += insn->size;
+					ip += iext->variant.branch.displacement;
+
+					if (ip != ev->variant.disabled.ip)
+						break;
+				}
 
 				/* Fall through. */
 			case ptic_return:
@@ -1117,6 +1123,9 @@
 	if (!decoder || !insn || !iext)
 		return -pte_internal;
 
+	/* Branch displacements apply to the next instruction. */
+	decoder->ip += insn->size;
+
 	/* We handle non-branches, non-taken conditional branches, and
 	 * compressed returns directly in the switch and do some pre-work for
 	 * calls.
@@ -1125,7 +1134,6 @@
 	 */
 	switch (insn->iclass) {
 	case ptic_other:
-		decoder->ip += insn->size;
 		return 0;
 
 	case ptic_cond_jump: {
@@ -1136,29 +1144,23 @@
 			return status;
 
 		decoder->status = status;
-		if (!taken) {
-			decoder->ip += insn->size;
+		if (!taken)
 			return 0;
-		}
 
 		break;
 	}
 
-	case ptic_call: {
-		uint64_t nip;
-
+	case ptic_call:
 		/* Log the call for return compression.
 		 *
 		 * Unless this is a call to the next instruction as is used
 		 * for position independent code.
 		 */
-		nip = decoder->ip + insn->size;
-		if (!iext->variant.branch.is_direct ||
-		    (nip != iext->variant.branch.target))
-			pt_retstack_push(&decoder->retstack, nip);
+		if (iext->variant.branch.displacement ||
+		    !iext->variant.branch.is_direct)
+			pt_retstack_push(&decoder->retstack, decoder->ip);
 
 		break;
-	}
 
 	case ptic_return: {
 		int taken, status;
@@ -1197,7 +1199,7 @@
 	 * and all flavors of far transfers.
 	 */
 	if (iext->variant.branch.is_direct)
-		decoder->ip = iext->variant.branch.target;
+		decoder->ip += iext->variant.branch.displacement;
 	else {
 		int status;