[RFC v5 23/57] objtool: arm64: Decode logical data processing instructions

From: Julien Thierry
Date: Thu Jan 09 2020 - 11:05:52 EST


Decode instructions performing logical operations with immediate values.
Create a stack operation for and operation targeting the stack pointer.

Since OP_SRC_AND assumes the source and destination register are the same,
add a register assignment operation when the source operand of the logical
instruction is not the stack pointer.

Suggested-by: Raphael Gault <raphael.gault@xxxxxxx>
Signed-off-by: Julien Thierry <jthierry@xxxxxxxxxx>
---
tools/objtool/arch/arm64/decode.c | 58 +++++++++++++++++++
.../objtool/arch/arm64/include/insn_decode.h | 3 +
2 files changed, 61 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index d240f29a2390..a30c3294cc21 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -160,6 +160,7 @@ static arm_decode_class aarch64_insn_dp_imm_decode_table[NR_DP_IMM_SUBCLASS] = {
[0 ... INSN_PCREL] = arm_decode_pcrel,
[INSN_ADD_SUB] = arm_decode_add_sub,
[INSN_ADD_TAG] = arm_decode_add_sub_tags,
+ [INSN_LOGICAL] = arm_decode_logical,
[INSN_MOVE_WIDE] = arm_decode_move_wide,
[INSN_BITFIELD] = arm_decode_bitfield,
[INSN_EXTRACT] = arm_decode_extract,
@@ -273,6 +274,63 @@ int arm_decode_add_sub_tags(u32 instr, enum insn_type *type,
return 0;
}

+int arm_decode_logical(u32 instr, enum insn_type *type,
+ unsigned long *immediate, struct list_head *ops_list)
+{
+ unsigned char sf = 0, opc = 0, N = 0;
+ unsigned char imms = 0, immr = 0, rn = 0, rd = 0;
+ struct stack_op *op;
+
+ rd = instr & ONES(5);
+ rn = (instr >> 5) & ONES(5);
+
+ imms = (instr >> 10) & ONES(6);
+ immr = (instr >> 16) & ONES(6);
+
+ N = EXTRACT_BIT(instr, 22);
+ opc = (instr >> 29) & ONES(2);
+ sf = EXTRACT_BIT(instr, 31);
+
+ if (N == 1 && sf == 0)
+ return arm_decode_unknown(instr, type, immediate, ops_list);
+
+ *type = INSN_OTHER;
+ *immediate = (decode_bit_masks(N, imms, immr, true) >> 64);
+
+ if (opc & 1)
+ return 0;
+
+ if (rd != CFI_SP)
+ return 0;
+
+ *type = INSN_STACK;
+
+ if (rn != CFI_SP) {
+ op = calloc(1, sizeof(*op));
+ list_add_tail(&op->list, ops_list);
+
+ op->dest.type = OP_DEST_REG;
+ op->dest.offset = 0;
+ op->dest.reg = rd;
+ op->src.type = OP_SRC_REG;
+ op->src.offset = 0;
+ op->src.reg = rn;
+ }
+
+ op = calloc(1, sizeof(*op));
+ list_add_tail(&op->list, ops_list);
+
+ op->dest.type = OP_DEST_REG;
+ op->dest.offset = 0;
+ op->dest.reg = rd;
+
+ op->src.type = OP_SRC_AND;
+ op->src.offset = 0;
+ op->src.reg = rd;
+
+ return 0;
+}
+
int arm_decode_move_wide(u32 instr, enum insn_type *type,
unsigned long *immediate, struct list_head *ops_list)
{
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 65e60b293a07..6f68e8887cdb 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -16,6 +16,7 @@
#define INSN_PCREL 0b001 //0b00x
#define INSN_ADD_SUB 0b010
#define INSN_ADD_TAG 0b011
+#define INSN_LOGICAL 0b100
#define INSN_MOVE_WIDE 0b101
#define INSN_BITFIELD 0b110
#define INSN_EXTRACT 0b111
@@ -38,6 +39,8 @@ int arm_decode_add_sub(u32 instr, enum insn_type *type,
int arm_decode_add_sub_tags(u32 instr, enum insn_type *type,
unsigned long *immediate,
struct list_head *ops_list);
+int arm_decode_logical(u32 instr, enum insn_type *type,
+ unsigned long *immediate, struct list_head *ops_list);
int arm_decode_move_wide(u32 instr, enum insn_type *type,
unsigned long *immediate, struct list_head *ops_list);
int arm_decode_bitfield(u32 instr, enum insn_type *type,
--
2.21.0