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;