From 36000b3ef0ebf029a384bbad65c4225aaab7cefc Mon Sep 17 00:00:00 2001 From: Enrico Deiana Date: Wed, 18 Dec 2024 09:28:47 -0800 Subject: [PATCH] i#6662 public traces: add instr_t operation_size API (#7151) Adds instr_get_operation_size() and instr_set_operation_size() public APIs for DR_ISA_REGDEPS instructions, which are currently the only instructions for which operation_size is defined. We set operation_size of DR_ISA_REGDEPS instructions with no operands to OPSZ_0 in the convertion to REGDEPS process, so decoded and converted instructions look the same. Previously a converted instruction might have had an operation_size different than OPSZ_0 even with no register operands, that would then be corrected during encoding and subsequent decoding. This is mostly for convenience when testing. We update a test to also invoke the instr_length() API on DR_ISA_REGDEPS instructions. Issue #6662 --- api/docs/release.dox | 3 ++- core/ir/instr_api.h | 16 ++++++++++++++++ core/ir/instr_shared.c | 29 +++++++++++++++++++++++++++-- suite/tests/api/ir_regdeps.c | 12 ++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/api/docs/release.dox b/api/docs/release.dox index 13312174afd..199355300e1 100644 --- a/api/docs/release.dox +++ b/api/docs/release.dox @@ -129,7 +129,8 @@ changes: - No compatibility changes yet. Further non-compatibility-affecting changes include: - - No changes yet. + - Added instr_get_operation_size() and instr_set_operation_size() APIs for + #DR_ISA_REGDEPS #instr_t. **************************************************
diff --git a/core/ir/instr_api.h b/core/ir/instr_api.h index 33f46c809b9..2dff45a4a42 100644 --- a/core/ir/instr_api.h +++ b/core/ir/instr_api.h @@ -1995,6 +1995,22 @@ DR_API instr_t * instr_convert_short_meta_jmp_to_long(void *drcontext, instrlist_t *ilist, instr_t *instr); +DR_API +/** + * Returns the operation size of \p instr if it's a #DR_ISA_REGDEPS instruction, #OPSZ_NA + * otherwise. + */ +opnd_size_t +instr_get_operation_size(instr_t *instr); + +DR_API +/** + * Sets the operation size of \p instr to \p operation_size only if instr is a + * #DR_ISA_REGDEPS instruction. + */ +void +instr_set_operation_size(instr_t *instr, opnd_size_t operation_size); + DR_API /** * Converts a real ISA (e.g., #DR_ISA_AMD64) instruction \p instr_real_isa into a diff --git a/core/ir/instr_shared.c b/core/ir/instr_shared.c index d61ab038787..89df9c237e2 100644 --- a/core/ir/instr_shared.c +++ b/core/ir/instr_shared.c @@ -2999,6 +2999,27 @@ instr_uses_fp_reg(instr_t *instr) return false; } +opnd_size_t +instr_get_operation_size(instr_t *instr) +{ + /* Only DR_ISA_REGDEPS instructions can have an operation_size. + */ + if (instr_get_isa_mode(instr) == DR_ISA_REGDEPS) + return instr->operation_size; + + return OPSZ_NA; +} + +void +instr_set_operation_size(instr_t *instr, opnd_size_t operation_size) +{ + CLIENT_ASSERT(instr_get_isa_mode(instr) != DR_ISA_REGDEPS, + "instr_set_operation_size: only DR_ISA_REGDEPS instructions can have " + "an operation_size"); + instr->operation_size = operation_size; + return; +} + void instr_convert_to_isa_regdeps(void *drcontext, instr_t *instr_real_isa, instr_t *instr_regdeps_isa) @@ -3097,10 +3118,14 @@ instr_convert_to_isa_regdeps(void *drcontext, instr_t *instr_real_isa, instr_set_category(instr_regdeps_isa, instr_get_category(instr_real_isa)); /* Convert max_src_opnd_size_bytes from number of bytes to opnd_size_t (which holds - * OPSZ_ enum values). + * OPSZ_ enum values). If we have no operands, operation_size is OPSZ_0, same as a + * decoded DR_ISA_REGDEPS instruction. */ opnd_size_t max_opnd_size = opnd_size_from_bytes(max_src_opnd_size_bytes); - instr_regdeps_isa->operation_size = max_opnd_size; + if (num_dsts + num_srcs > 0) + instr_regdeps_isa->operation_size = max_opnd_size; + else + instr_regdeps_isa->operation_size = OPSZ_0; /* Set the source and destination register operands for the converted instruction. */ diff --git a/suite/tests/api/ir_regdeps.c b/suite/tests/api/ir_regdeps.c index 739336840db..b4da7795ef7 100644 --- a/suite/tests/api/ir_regdeps.c +++ b/suite/tests/api/ir_regdeps.c @@ -108,11 +108,23 @@ test_instr_encode_decode_disassemble_synthetic(void *dc, instr_t *instr, byte *next_pc_decode = decode(dc, bytes, instr_synthetic_decoded); ASSERT(next_pc_decode != NULL); ASSERT(next_pc_encode == next_pc_decode); + + /* Check instruction length. + */ + ASSERT((next_pc_encode - bytes) == instr_length(dc, instr_synthetic_decoded)); + ASSERT(instr_length(dc, instr_synthetic_decoded) != 0); + /* Check for overflow. */ ASSERT((next_pc_encode - bytes) <= sizeof(bytes)); ASSERT((next_pc_decode - bytes) <= sizeof(bytes)); + /* Check operation size. + */ + ASSERT(instr_get_operation_size(instr_synthetic_decoded) != OPSZ_NA); + ASSERT(instr_get_operation_size(instr_synthetic_decoded) == + instr_get_operation_size(instr_synthetic_converted)); + /* Disassemble regdeps synthetic encodings to buffer. */ char dbuf[512];