From: madvenka@linux.microsoft.com
To: jpoimboe@redhat.com, peterz@infradead.org,
chenzhongjin@huawei.com, mark.rutland@arm.com,
broonie@kernel.org, nobuta.keiya@fujitsu.com,
sjitindarsingh@gmail.com, catalin.marinas@arm.com,
will@kernel.org, jamorris@linux.microsoft.com,
linux-arm-kernel@lists.infradead.org,
live-patching@vger.kernel.org, linux-kernel@vger.kernel.org,
madvenka@linux.microsoft.com
Subject: [RFC PATCH v3 10/22] objtool: arm64: Implement decoder for Dynamic FP validation
Date: Thu, 2 Feb 2023 01:40:24 -0600 [thread overview]
Message-ID: <20230202074036.507249-11-madvenka@linux.microsoft.com> (raw)
In-Reply-To: <20230202074036.507249-1-madvenka@linux.microsoft.com>
From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>
Implement arch_decode_instruction() for ARM64. For Dynamic FP validation,
we need to walk each function's code and determine the stack and frame
offsets at each instruction. So, the following instructions are completely
decoded:
Instructions that affect the SP and FP:
- Load-Store instructions
- Add/Sub/Mov instructions
Instructions that affect control flow:
- Branch instructions
- Call instructions
- Return instructions
Miscellaneous instructions:
- Break instruction used for bugs
- Paciasp instruction that occurs at the beginning of the frame
pointer prolog
The rest of the instructions are either dont-care from an unwind
perspective or unexpected from the compiler. Add checks for the unexpected
ones to catch them if the compiler ever generates them.
Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
tools/objtool/arch/arm64/decode.c | 506 ++++++++++++++++++++++++++-
tools/objtool/include/objtool/arch.h | 2 +
2 files changed, 507 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 69f851337537..aaae16791807 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
+ * decode.c - ARM64 instruction decoder for dynamic FP validation. Only a
+ * small subset of the instructions need to be decoded. The rest
+ * only need to be sanity checked.
+ *
* Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com)
*
* Copyright (C) 2022 Microsoft Corporation
@@ -7,15 +11,515 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <objtool/check.h>
+#include <objtool/elf.h>
+#include <objtool/warn.h>
+
+/* ARM64 instructions are all 4 bytes wide. */
+#define INSN_SIZE 4
+
+/* --------------------- instruction decode structs ------------------------ */
+
+struct decode_var {
+ u32 insn;
+ enum insn_type type;
+ s64 imm;
+ unsigned int mode1;
+ unsigned int mode2;
+ unsigned int check_reg;
+ struct list_head *ops;
+};
+
+struct decode {
+ unsigned long opmask;
+ unsigned long op;
+ unsigned int width;
+ unsigned int shift;
+ unsigned int bits;
+ unsigned int sign_extend;
+ unsigned int mult;
+ unsigned int mode1;
+ unsigned int mode2;
+ void (*func)(struct decode *decode, struct decode_var *var);
+};
+
+struct class {
+ unsigned long opmask;
+ unsigned long op;
+ void (*check)(struct decode_var *var);
+};
+
+/* ------------------------ stack operations ------------------------------- */
+
+static void add_stack_op(unsigned char src_reg, enum op_src_type src_type,
+ s64 src_offset,
+ unsigned char dest_reg, enum op_dest_type dest_type,
+ s64 dest_offset,
+ struct list_head *ops)
+{
+ struct stack_op *op;
+
+ op = calloc(1, sizeof(*op));
+ if (!op) {
+ WARN("calloc failed");
+ return;
+ }
+
+ op->src.reg = src_reg;
+ op->src.type = src_type;
+ op->src.offset = src_offset;
+ op->dest.reg = dest_reg;
+ op->dest.type = dest_type;
+ op->dest.offset = dest_offset;
+
+ list_add_tail(&op->list, ops);
+}
+
+static void add_op(struct decode_var *var,
+ unsigned char rn, s64 offset, unsigned char rd)
+{
+ add_stack_op(rn, OP_SRC_ADD, offset, rd, OP_DEST_REG, 0, var->ops);
+}
+
+static void load_op(struct decode_var *var, s64 offset, unsigned char rd)
+{
+ add_stack_op(CFI_SP, OP_SRC_REG_INDIRECT, offset, rd, OP_DEST_REG, 0,
+ var->ops);
+}
+
+static void store_op(struct decode_var *var, s64 offset, unsigned char rd)
+{
+ add_stack_op(CFI_SP, OP_SRC_REG, 0, rd, OP_DEST_REG_INDIRECT, offset,
+ var->ops);
+}
+
+/* ------------------------ decode functions ------------------------------- */
+
+#define is_saved_reg(rt) ((rt) == CFI_FP || (rt) == CFI_RA)
+#define is_frame_reg(rt) ((rt) == CFI_FP || (rt) == CFI_SP)
+
+/* ----- Add/Subtract instructions. ----- */
+
+#define CMN_OP 0x31000000 /* Alias of ADDS imm */
+#define CMP_OP 0x71000000 /* Alias of SUBS imm */
+
+static void add(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ unsigned int shift = (var->insn >> 22) & 1;
+
+ if (decode->op == CMN_OP || decode->op == CMP_OP)
+ return;
+
+ if (!is_frame_reg(rd))
+ return;
+
+ if (is_frame_reg(rn)) {
+ if (shift)
+ var->imm <<= 12;
+ add_op(var, rn, var->imm, rd);
+ } else {
+ var->type = INSN_UNRELIABLE;
+ }
+}
+
+#define CMN_EXT_OP 0x2B200000 /* Alias of ADDS ext */
+#define CMP_EXT_OP 0x6B200000 /* Alias of SUBS ext */
+
+static void addc(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+
+ if (decode->op == CMN_EXT_OP || decode->op == CMP_EXT_OP)
+ return;
+
+ if (is_frame_reg(rd))
+ var->type = INSN_UNRELIABLE;
+}
+
+static void sub(struct decode *decode, struct decode_var *var)
+{
+ var->imm = -var->imm;
+ return add(decode, var);
+}
+
+/* ----- Load instructions. ----- */
+
+/*
+ * For some instructions, the target register cannot be FP. There are 3 cases:
+ *
+ * - The register width is 32 bits. FP cannot be 32 bits.
+ * - The register is loaded from one that is not the SP. We do not track
+ * the value of other registers in static analysis.
+ * - The instruction does not make sense for the FP to be the target.
+ */
+static void check_reg(unsigned int reg, struct decode_var *var)
+{
+ if (reg == CFI_FP)
+ var->type = INSN_UNRELIABLE;
+}
+
+static void ldp(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rt1 = var->insn & 0x1F;
+ unsigned int rt2 = (var->insn >> 10) & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (rn != CFI_SP || var->check_reg) {
+ check_reg(rt1, var);
+ check_reg(rt2, var);
+ }
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rt1))
+ load_op(var, imm, rt1);
+ if (is_saved_reg(rt2))
+ load_op(var, imm + 8, rt2);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+static void ldpc(struct decode *decode, struct decode_var *var)
+{
+ var->check_reg = 1;
+ ldp(decode, var);
+}
+
+static void ldr(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (rn != CFI_SP || var->check_reg)
+ check_reg(rd, var);
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rd))
+ load_op(var, imm, rd);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+/* ----- Store instructions. ----- */
+
+static void stp(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rt1 = var->insn & 0x1F;
+ unsigned int rt2 = (var->insn >> 10) & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (var->check_reg) {
+ check_reg(rt1, var);
+ check_reg(rt2, var);
+ }
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rt1))
+ store_op(var, imm, rt1);
+ if (is_saved_reg(rt2))
+ store_op(var, imm + 8, rt2);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+static void stpc(struct decode *decode, struct decode_var *var)
+{
+ var->check_reg = 1;
+ stp(decode, var);
+}
+
+static void str(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (var->check_reg)
+ check_reg(rd, var);
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rd))
+ store_op(var, imm, rd);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+static void strc(struct decode *decode, struct decode_var *var)
+{
+ var->check_reg = 1;
+ str(decode, var);
+}
+
+/* ----- Control transfer instructions. ----- */
+
+#define BR_UNCONDITIONAL 0x14000000
+
+static void bra(struct decode *decode, struct decode_var *var)
+{
+ if (var->imm) {
+ if (decode->op == BR_UNCONDITIONAL)
+ var->type = INSN_JUMP_UNCONDITIONAL;
+ else
+ var->type = INSN_JUMP_CONDITIONAL;
+ } else {
+ var->type = INSN_JUMP_DYNAMIC;
+ }
+}
+
+static void call(struct decode *decode, struct decode_var *var)
+{
+ var->type = var->imm ? INSN_CALL : INSN_CALL_DYNAMIC;
+}
+
+static void ret(struct decode *decode, struct decode_var *var)
+{
+ var->type = INSN_RETURN;
+}
+
+/* ----- Miscellaneous instructions. ----- */
+
+static void bug(struct decode *decode, struct decode_var *var)
+{
+ var->type = INSN_BUG;
+}
+
+static void pac(struct decode *decode, struct decode_var *var)
+{
+ var->type = INSN_START;
+}
+
+/* ------------------------ Instruction decode ----------------------------- */
+
+struct decode decode_array[] = {
+/*
+ * mask OP code mask
+ * opcode OP code
+ * width Target register width. Values can be:
+ * 64 (64-bit)
+ * 32 (32-bit),
+ * X (64-bit if bit X in the instruction is set)
+ * -X (32-bit if bit X in the instruction is set)
+ * shift Shift for the immediate value
+ * bits Number of bits in the immediate value
+ * sign Sign extend the immediate value
+ * mult Multiplier for the immediate value
+ * am1 Addressing mode bit 1
+ * am2 Addressing mode bit 2
+ * func Decode function
+ *
+ * =============================== INSTRUCTIONS ===============================
+ * mask opcode width shift bits sign mult am1 am2 func
+ * ============================================================================
+ */
+{ 0x7E400000, 0x28400000, 31, 15, 7, 1, 0, 23, 24, ldp /* LDP */},
+{ 0x7E400000, 0x68400000, 32, 15, 7, 1, 4, 23, 24, ldp /* LDPSW */},
+{ 0x7FC00000, 0x28400000, 31, 15, 7, 1, 0, 0, 0, ldpc /* LDNP */},
+{ 0xBFE00000, 0xB8400000, 30, 12, 9, 1, 1, 10, 11, ldr /* LDR */},
+{ 0xBFC00000, 0xB9400000, 30, 10, 12, 0, 0, 0, 0, ldr /* LDR off */},
+{ 0xFF200400, 0xF8200400, 64, 12, 9, 1, 8, 11, 11, ldr /* LDRA */},
+{ 0xFFC00000, 0x39400000, 32, 10, 12, 0, 1, 0, 0, ldr /* LDRB off */},
+{ 0xFFE00000, 0x38400000, 32, 12, 9, 1, 1, 10, 11, ldr /* LDRB */},
+{ 0xFFC00000, 0x79400000, 32, 10, 12, 0, 2, 0, 0, ldr /* LDRH off */},
+{ 0xFFE00000, 0x78400000, 32, 12, 9, 1, 1, 10, 11, ldr /* LDRH */},
+{ 0xFF800000, 0x39800000, -22, 10, 12, 0, 1, 0, 0, ldr /* LDRSB off */},
+{ 0xFFA00000, 0x38800000, -22, 12, 9, 1, 1, 10, 11, ldr /* LDRSB */},
+{ 0xFF800000, 0x79800000, -22, 10, 12, 0, 2, 0, 0, ldr /* LDRSH off */},
+{ 0xFFA00000, 0x78800000, -22, 12, 9, 1, 1, 10, 11, ldr /* LDRSH */},
+{ 0xFFC00000, 0xB9800000, 32, 10, 12, 0, 4, 0, 0, ldr /* LDRSW off */},
+{ 0xFFE00000, 0xB8800000, 32, 12, 9, 1, 1, 10, 11, ldr /* LDRSW */},
+{ 0x7E000000, 0x28000000, 31, 15, 7, 1, 0, 23, 24, stp /* STP */},
+{ 0x7E400000, 0x28000000, 31, 15, 7, 1, 0, 23, 24, stp /* STG */},
+{ 0xFE400000, 0x68000000, 64, 15, 7, 1, 16, 23, 24, stpc /* STGP */},
+{ 0x7FC00000, 0x28000000, 31, 15, 7, 1, 0, 0, 0, stpc /* STNP */},
+{ 0xBFC00000, 0xB9000000, 30, 10, 12, 0, 0, 0, 0, str /* STR off */},
+{ 0xBFE00000, 0xB8000000, 30, 12, 9, 1, 1, 10, 11, str /* STR */},
+{ 0xFFE00000, 0xD9200000, 64, 12, 9, 1, 16, 10, 11, strc /* STG */},
+{ 0xFFE00000, 0xD9A00000, 64, 12, 9, 1, 16, 10, 11, strc /* ST2G */},
+{ 0x7F800000, 0x11000000, 31, 10, 12, 0, 1, 0, 0, add /* ADD imm */},
+{ 0x7FE00000, 0x0B200000, 31, 10, 3, 0, 1, 0, 0, addc /* ADD ext */},
+{ 0x7F800000, 0x31000000, 31, 10, 12, 0, 1, 0, 0, add /* ADDS imm */},
+{ 0x7FE00000, 0x2B200000, 31, 10, 3, 0, 1, 0, 0, addc /* ADDS ext */},
+{ 0x7F800000, 0x51000000, 31, 10, 12, 0, 1, 0, 0, sub /* SUB imm */},
+{ 0x7FE00000, 0x4B200000, 31, 10, 3, 0, 1, 0, 0, addc /* SUB ext */},
+{ 0x7F800000, 0x71000000, 31, 10, 12, 0, 1, 0, 0, sub /* SUBS imm */},
+{ 0x7FE00000, 0x6B200000, 31, 10, 3, 0, 1, 0, 0, addc /* SUBS ext */},
+{ 0xFC000000, 0x14000000, 64, 0, 26, 1, 4, 0, 0, bra /* B */},
+{ 0xFF000010, 0x54000000, 64, 5, 19, 1, 4, 0, 0, bra /* B.cond */},
+{ 0xFF000010, 0x54000010, 64, 5, 19, 1, 4, 0, 0, bra /* BC.cond */},
+{ 0xFFFFFC1F, 0xD61F0000, 64, 0, 0, 0, 0, 0, 0, bra /* BR */},
+{ 0xFEFFF800, 0xD61F0800, 64, 0, 0, 0, 0, 0, 0, bra /* BRA */},
+{ 0x7E000000, 0x34000000, 31, 5, 19, 1, 4, 0, 0, bra /* CBZ/CBNZ */},
+{ 0x7E000000, 0x36000000, 31, 5, 14, 1, 4, 0, 0, bra /* TBZ/TBNZ */},
+{ 0xFC000000, 0x94000000, 64, 0, 26, 1, 4, 0, 0, call /* BL */},
+{ 0xFFFFFC1F, 0xD63F0000, 64, 0, 0, 0, 0, 0, 0, call /* BLR */},
+{ 0xFEFFF800, 0xD63F0800, 64, 0, 0, 0, 0, 0, 0, call /* BLRA */},
+{ 0xFFFFFC1F, 0xD65F0000, 64, 0, 0, 0, 0, 0, 0, ret /* RET */},
+{ 0xFFFFFBFF, 0xD65F0BFF, 64, 0, 0, 0, 0, 0, 0, ret /* RETA */},
+{ 0xFFFFFFFF, 0xD69F03E0, 64, 0, 0, 0, 0, 0, 0, ret /* ERET */},
+{ 0xFFFFFBFF, 0xD69F0BFF, 64, 0, 0, 0, 0, 0, 0, ret /* ERETA */},
+{ 0xFFE00000, 0xD4200000, 64, 5, 16, 0, 1, 0, 0, bug /* BRK */},
+{ 0xFFFFFFFF, 0xD503233F, 64, 0, 0, 0, 1, 0, 0, pac /* PACIASP */},
+};
+unsigned int ndecode = ARRAY_SIZE(decode_array);
+
+static void ignore(struct decode_var *var)
+{
+}
+
+static void check_target(struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+
+ check_reg(rd, var);
+}
+
+struct class class_array[] = {
+/*
+ * mask Class OP mask
+ * opcode Class OP code
+ * check Function to perform checks
+ *
+ * ========================== INSTRUCTION CLASSES =============================
+ * mask opcode check
+ * ============================================================================
+ */
+{ 0x1E000000, 0x00000000, ignore /* RSVD_00 */ },
+{ 0x1E000000, 0x02000000, ignore /* UNALLOC_01 */ },
+{ 0x1E000000, 0x04000000, ignore /* SVE_02 */ },
+{ 0x1E000000, 0x06000000, ignore /* UNALLOC_03 */ },
+{ 0x1E000000, 0x08000000, check_target /* LOAD_STORE_04 */ },
+{ 0x1E000000, 0x0A000000, check_target /* DP_REGISTER_05 */ },
+{ 0x1E000000, 0x0C000000, ignore /* LOAD_STORE_06 */ },
+{ 0x1E000000, 0x0E000000, ignore /* SIMD_FP_07 */ },
+{ 0x1E000000, 0x12000000, check_target /* DP_IMMEDIATE_09 */ },
+{ 0x1E000000, 0x10000000, check_target /* DP_IMMEDIATE_08 */ },
+{ 0x1E000000, 0x14000000, check_target /* BR_SYS_10 */ },
+{ 0x1E000000, 0x16000000, check_target /* BR_SYS_11 */ },
+{ 0x1E000000, 0x18000000, check_target /* LOAD_STORE_12 */ },
+{ 0x1E000000, 0x1A000000, ignore /* DP_REGISTER_13 */ },
+{ 0x1E000000, 0x1C000000, check_target /* LOAD_STORE_14 */ },
+{ 0x1E000000, 0x1E000000, ignore /* SIMD_FP_15 */ },
+};
+unsigned int nclass = ARRAY_SIZE(class_array);
+
+static inline s64 sign_extend(s64 imm, unsigned int bits)
+{
+ return (imm << (64 - bits)) >> (64 - bits);
+}
int arch_decode_instruction(struct objtool_file *file,
const struct section *sec,
unsigned long offset, unsigned int maxlen,
unsigned int *len, enum insn_type *type,
unsigned long *immediate,
- struct list_head *ops_list)
+ struct list_head *ops)
{
+ struct decode *decode;
+ struct decode_var var;
+ struct class *class;
+ unsigned int width, mask, mult, i;
+
+ if (maxlen < INSN_SIZE)
+ return -1;
+ *len = INSN_SIZE;
+
+ var.insn = *(u32 *)(sec->data->d_buf + offset);
+ var.type = INSN_OTHER;
+ var.imm = 0;
+ var.ops = ops;
+
+ *type = INSN_OTHER;
+
+ /* Decode the instruction, if listed. */
+ for (i = 0; i < ndecode; i++) {
+ decode = &decode_array[i];
+
+ if ((var.insn & decode->opmask) != decode->op)
+ continue;
+
+ /* Extract addressing mode (for some instructions). */
+ var.mode1 = 0;
+ var.mode2 = 0;
+ if (decode->mode1)
+ var.mode1 = (var.insn >> decode->mode1) & 1;
+ if (decode->mode2)
+ var.mode2 = (var.insn >> decode->mode2) & 1;
+
+ /* Determine target register width. */
+ width = decode->width;
+ if (width < 0)
+ width = (var.insn & (1 << -width)) ? 32 : 64;
+ else if (width < 32)
+ width = (var.insn & (1 << width)) ? 64 : 32;
+
+ /*
+ * If the target register width is 32 bits, set the check flag
+ * so that the target registers are checked to make sure they
+ * are not the FP or the RA. We should not be using 32-bit
+ * values in these registers.
+ */
+ var.check_reg = (width == 32);
+
+ /* Extract the immediate value. */
+ mask = (1 << decode->bits) - 1;
+ var.imm = (var.insn >> decode->shift) & mask;
+ if (decode->sign_extend)
+ var.imm = sign_extend(var.imm, decode->bits);
+
+ /* Scale the immediate value. */
+ mult = decode->mult;
+ if (!mult)
+ mult = (width == 32) ? 4 : 8;
+ var.imm *= mult;
+
+ /* Decode the instruction. */
+ decode->func(decode, &var);
+ goto out;
+ }
+
+ /*
+ * Sanity check to make sure that the compiler has not generated
+ * code that modifies the FP or the RA in an unexpected way.
+ */
+ for (i = 0; i < nclass; i++) {
+ class = &class_array[i];
+ if ((var.insn & class->opmask) == class->op) {
+ class->check(&var);
+ goto out;
+ }
+ }
+out:
+ *immediate = var.imm;
+ *type = var.type;
return 0;
}
diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h
index beb2f3aa94ff..3c2f8c1b8265 100644
--- a/tools/objtool/include/objtool/arch.h
+++ b/tools/objtool/include/objtool/arch.h
@@ -29,6 +29,8 @@ enum insn_type {
INSN_TRAP,
INSN_ENDBR,
INSN_OTHER,
+ INSN_START,
+ INSN_UNRELIABLE,
};
enum op_dest_type {
--
2.25.1
WARNING: multiple messages have this Message-ID (diff)
From: madvenka@linux.microsoft.com
To: jpoimboe@redhat.com, peterz@infradead.org,
chenzhongjin@huawei.com, mark.rutland@arm.com,
broonie@kernel.org, nobuta.keiya@fujitsu.com,
sjitindarsingh@gmail.com, catalin.marinas@arm.com,
will@kernel.org, jamorris@linux.microsoft.com,
linux-arm-kernel@lists.infradead.org,
live-patching@vger.kernel.org, linux-kernel@vger.kernel.org,
madvenka@linux.microsoft.com
Subject: [RFC PATCH v3 10/22] objtool: arm64: Implement decoder for Dynamic FP validation
Date: Thu, 2 Feb 2023 01:40:24 -0600 [thread overview]
Message-ID: <20230202074036.507249-11-madvenka@linux.microsoft.com> (raw)
In-Reply-To: <20230202074036.507249-1-madvenka@linux.microsoft.com>
From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>
Implement arch_decode_instruction() for ARM64. For Dynamic FP validation,
we need to walk each function's code and determine the stack and frame
offsets at each instruction. So, the following instructions are completely
decoded:
Instructions that affect the SP and FP:
- Load-Store instructions
- Add/Sub/Mov instructions
Instructions that affect control flow:
- Branch instructions
- Call instructions
- Return instructions
Miscellaneous instructions:
- Break instruction used for bugs
- Paciasp instruction that occurs at the beginning of the frame
pointer prolog
The rest of the instructions are either dont-care from an unwind
perspective or unexpected from the compiler. Add checks for the unexpected
ones to catch them if the compiler ever generates them.
Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
tools/objtool/arch/arm64/decode.c | 506 ++++++++++++++++++++++++++-
tools/objtool/include/objtool/arch.h | 2 +
2 files changed, 507 insertions(+), 1 deletion(-)
diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 69f851337537..aaae16791807 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
+ * decode.c - ARM64 instruction decoder for dynamic FP validation. Only a
+ * small subset of the instructions need to be decoded. The rest
+ * only need to be sanity checked.
+ *
* Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com)
*
* Copyright (C) 2022 Microsoft Corporation
@@ -7,15 +11,515 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <objtool/check.h>
+#include <objtool/elf.h>
+#include <objtool/warn.h>
+
+/* ARM64 instructions are all 4 bytes wide. */
+#define INSN_SIZE 4
+
+/* --------------------- instruction decode structs ------------------------ */
+
+struct decode_var {
+ u32 insn;
+ enum insn_type type;
+ s64 imm;
+ unsigned int mode1;
+ unsigned int mode2;
+ unsigned int check_reg;
+ struct list_head *ops;
+};
+
+struct decode {
+ unsigned long opmask;
+ unsigned long op;
+ unsigned int width;
+ unsigned int shift;
+ unsigned int bits;
+ unsigned int sign_extend;
+ unsigned int mult;
+ unsigned int mode1;
+ unsigned int mode2;
+ void (*func)(struct decode *decode, struct decode_var *var);
+};
+
+struct class {
+ unsigned long opmask;
+ unsigned long op;
+ void (*check)(struct decode_var *var);
+};
+
+/* ------------------------ stack operations ------------------------------- */
+
+static void add_stack_op(unsigned char src_reg, enum op_src_type src_type,
+ s64 src_offset,
+ unsigned char dest_reg, enum op_dest_type dest_type,
+ s64 dest_offset,
+ struct list_head *ops)
+{
+ struct stack_op *op;
+
+ op = calloc(1, sizeof(*op));
+ if (!op) {
+ WARN("calloc failed");
+ return;
+ }
+
+ op->src.reg = src_reg;
+ op->src.type = src_type;
+ op->src.offset = src_offset;
+ op->dest.reg = dest_reg;
+ op->dest.type = dest_type;
+ op->dest.offset = dest_offset;
+
+ list_add_tail(&op->list, ops);
+}
+
+static void add_op(struct decode_var *var,
+ unsigned char rn, s64 offset, unsigned char rd)
+{
+ add_stack_op(rn, OP_SRC_ADD, offset, rd, OP_DEST_REG, 0, var->ops);
+}
+
+static void load_op(struct decode_var *var, s64 offset, unsigned char rd)
+{
+ add_stack_op(CFI_SP, OP_SRC_REG_INDIRECT, offset, rd, OP_DEST_REG, 0,
+ var->ops);
+}
+
+static void store_op(struct decode_var *var, s64 offset, unsigned char rd)
+{
+ add_stack_op(CFI_SP, OP_SRC_REG, 0, rd, OP_DEST_REG_INDIRECT, offset,
+ var->ops);
+}
+
+/* ------------------------ decode functions ------------------------------- */
+
+#define is_saved_reg(rt) ((rt) == CFI_FP || (rt) == CFI_RA)
+#define is_frame_reg(rt) ((rt) == CFI_FP || (rt) == CFI_SP)
+
+/* ----- Add/Subtract instructions. ----- */
+
+#define CMN_OP 0x31000000 /* Alias of ADDS imm */
+#define CMP_OP 0x71000000 /* Alias of SUBS imm */
+
+static void add(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ unsigned int shift = (var->insn >> 22) & 1;
+
+ if (decode->op == CMN_OP || decode->op == CMP_OP)
+ return;
+
+ if (!is_frame_reg(rd))
+ return;
+
+ if (is_frame_reg(rn)) {
+ if (shift)
+ var->imm <<= 12;
+ add_op(var, rn, var->imm, rd);
+ } else {
+ var->type = INSN_UNRELIABLE;
+ }
+}
+
+#define CMN_EXT_OP 0x2B200000 /* Alias of ADDS ext */
+#define CMP_EXT_OP 0x6B200000 /* Alias of SUBS ext */
+
+static void addc(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+
+ if (decode->op == CMN_EXT_OP || decode->op == CMP_EXT_OP)
+ return;
+
+ if (is_frame_reg(rd))
+ var->type = INSN_UNRELIABLE;
+}
+
+static void sub(struct decode *decode, struct decode_var *var)
+{
+ var->imm = -var->imm;
+ return add(decode, var);
+}
+
+/* ----- Load instructions. ----- */
+
+/*
+ * For some instructions, the target register cannot be FP. There are 3 cases:
+ *
+ * - The register width is 32 bits. FP cannot be 32 bits.
+ * - The register is loaded from one that is not the SP. We do not track
+ * the value of other registers in static analysis.
+ * - The instruction does not make sense for the FP to be the target.
+ */
+static void check_reg(unsigned int reg, struct decode_var *var)
+{
+ if (reg == CFI_FP)
+ var->type = INSN_UNRELIABLE;
+}
+
+static void ldp(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rt1 = var->insn & 0x1F;
+ unsigned int rt2 = (var->insn >> 10) & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (rn != CFI_SP || var->check_reg) {
+ check_reg(rt1, var);
+ check_reg(rt2, var);
+ }
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rt1))
+ load_op(var, imm, rt1);
+ if (is_saved_reg(rt2))
+ load_op(var, imm + 8, rt2);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+static void ldpc(struct decode *decode, struct decode_var *var)
+{
+ var->check_reg = 1;
+ ldp(decode, var);
+}
+
+static void ldr(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (rn != CFI_SP || var->check_reg)
+ check_reg(rd, var);
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rd))
+ load_op(var, imm, rd);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+/* ----- Store instructions. ----- */
+
+static void stp(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rt1 = var->insn & 0x1F;
+ unsigned int rt2 = (var->insn >> 10) & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (var->check_reg) {
+ check_reg(rt1, var);
+ check_reg(rt2, var);
+ }
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rt1))
+ store_op(var, imm, rt1);
+ if (is_saved_reg(rt2))
+ store_op(var, imm + 8, rt2);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+static void stpc(struct decode *decode, struct decode_var *var)
+{
+ var->check_reg = 1;
+ stp(decode, var);
+}
+
+static void str(struct decode *decode, struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+ unsigned int rn = (var->insn >> 5) & 0x1F;
+ s64 imm;
+
+ if (var->check_reg)
+ check_reg(rd, var);
+
+ if (rn == CFI_SP) {
+ if (var->mode1 && var->mode2) /* Pre-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+
+ imm = var->mode1 ? 0 : var->imm;
+ if (is_saved_reg(rd))
+ store_op(var, imm, rd);
+
+ if (var->mode1 && !var->mode2) /* Post-index */
+ add_op(var, CFI_SP, var->imm, CFI_SP);
+ }
+}
+
+static void strc(struct decode *decode, struct decode_var *var)
+{
+ var->check_reg = 1;
+ str(decode, var);
+}
+
+/* ----- Control transfer instructions. ----- */
+
+#define BR_UNCONDITIONAL 0x14000000
+
+static void bra(struct decode *decode, struct decode_var *var)
+{
+ if (var->imm) {
+ if (decode->op == BR_UNCONDITIONAL)
+ var->type = INSN_JUMP_UNCONDITIONAL;
+ else
+ var->type = INSN_JUMP_CONDITIONAL;
+ } else {
+ var->type = INSN_JUMP_DYNAMIC;
+ }
+}
+
+static void call(struct decode *decode, struct decode_var *var)
+{
+ var->type = var->imm ? INSN_CALL : INSN_CALL_DYNAMIC;
+}
+
+static void ret(struct decode *decode, struct decode_var *var)
+{
+ var->type = INSN_RETURN;
+}
+
+/* ----- Miscellaneous instructions. ----- */
+
+static void bug(struct decode *decode, struct decode_var *var)
+{
+ var->type = INSN_BUG;
+}
+
+static void pac(struct decode *decode, struct decode_var *var)
+{
+ var->type = INSN_START;
+}
+
+/* ------------------------ Instruction decode ----------------------------- */
+
+struct decode decode_array[] = {
+/*
+ * mask OP code mask
+ * opcode OP code
+ * width Target register width. Values can be:
+ * 64 (64-bit)
+ * 32 (32-bit),
+ * X (64-bit if bit X in the instruction is set)
+ * -X (32-bit if bit X in the instruction is set)
+ * shift Shift for the immediate value
+ * bits Number of bits in the immediate value
+ * sign Sign extend the immediate value
+ * mult Multiplier for the immediate value
+ * am1 Addressing mode bit 1
+ * am2 Addressing mode bit 2
+ * func Decode function
+ *
+ * =============================== INSTRUCTIONS ===============================
+ * mask opcode width shift bits sign mult am1 am2 func
+ * ============================================================================
+ */
+{ 0x7E400000, 0x28400000, 31, 15, 7, 1, 0, 23, 24, ldp /* LDP */},
+{ 0x7E400000, 0x68400000, 32, 15, 7, 1, 4, 23, 24, ldp /* LDPSW */},
+{ 0x7FC00000, 0x28400000, 31, 15, 7, 1, 0, 0, 0, ldpc /* LDNP */},
+{ 0xBFE00000, 0xB8400000, 30, 12, 9, 1, 1, 10, 11, ldr /* LDR */},
+{ 0xBFC00000, 0xB9400000, 30, 10, 12, 0, 0, 0, 0, ldr /* LDR off */},
+{ 0xFF200400, 0xF8200400, 64, 12, 9, 1, 8, 11, 11, ldr /* LDRA */},
+{ 0xFFC00000, 0x39400000, 32, 10, 12, 0, 1, 0, 0, ldr /* LDRB off */},
+{ 0xFFE00000, 0x38400000, 32, 12, 9, 1, 1, 10, 11, ldr /* LDRB */},
+{ 0xFFC00000, 0x79400000, 32, 10, 12, 0, 2, 0, 0, ldr /* LDRH off */},
+{ 0xFFE00000, 0x78400000, 32, 12, 9, 1, 1, 10, 11, ldr /* LDRH */},
+{ 0xFF800000, 0x39800000, -22, 10, 12, 0, 1, 0, 0, ldr /* LDRSB off */},
+{ 0xFFA00000, 0x38800000, -22, 12, 9, 1, 1, 10, 11, ldr /* LDRSB */},
+{ 0xFF800000, 0x79800000, -22, 10, 12, 0, 2, 0, 0, ldr /* LDRSH off */},
+{ 0xFFA00000, 0x78800000, -22, 12, 9, 1, 1, 10, 11, ldr /* LDRSH */},
+{ 0xFFC00000, 0xB9800000, 32, 10, 12, 0, 4, 0, 0, ldr /* LDRSW off */},
+{ 0xFFE00000, 0xB8800000, 32, 12, 9, 1, 1, 10, 11, ldr /* LDRSW */},
+{ 0x7E000000, 0x28000000, 31, 15, 7, 1, 0, 23, 24, stp /* STP */},
+{ 0x7E400000, 0x28000000, 31, 15, 7, 1, 0, 23, 24, stp /* STG */},
+{ 0xFE400000, 0x68000000, 64, 15, 7, 1, 16, 23, 24, stpc /* STGP */},
+{ 0x7FC00000, 0x28000000, 31, 15, 7, 1, 0, 0, 0, stpc /* STNP */},
+{ 0xBFC00000, 0xB9000000, 30, 10, 12, 0, 0, 0, 0, str /* STR off */},
+{ 0xBFE00000, 0xB8000000, 30, 12, 9, 1, 1, 10, 11, str /* STR */},
+{ 0xFFE00000, 0xD9200000, 64, 12, 9, 1, 16, 10, 11, strc /* STG */},
+{ 0xFFE00000, 0xD9A00000, 64, 12, 9, 1, 16, 10, 11, strc /* ST2G */},
+{ 0x7F800000, 0x11000000, 31, 10, 12, 0, 1, 0, 0, add /* ADD imm */},
+{ 0x7FE00000, 0x0B200000, 31, 10, 3, 0, 1, 0, 0, addc /* ADD ext */},
+{ 0x7F800000, 0x31000000, 31, 10, 12, 0, 1, 0, 0, add /* ADDS imm */},
+{ 0x7FE00000, 0x2B200000, 31, 10, 3, 0, 1, 0, 0, addc /* ADDS ext */},
+{ 0x7F800000, 0x51000000, 31, 10, 12, 0, 1, 0, 0, sub /* SUB imm */},
+{ 0x7FE00000, 0x4B200000, 31, 10, 3, 0, 1, 0, 0, addc /* SUB ext */},
+{ 0x7F800000, 0x71000000, 31, 10, 12, 0, 1, 0, 0, sub /* SUBS imm */},
+{ 0x7FE00000, 0x6B200000, 31, 10, 3, 0, 1, 0, 0, addc /* SUBS ext */},
+{ 0xFC000000, 0x14000000, 64, 0, 26, 1, 4, 0, 0, bra /* B */},
+{ 0xFF000010, 0x54000000, 64, 5, 19, 1, 4, 0, 0, bra /* B.cond */},
+{ 0xFF000010, 0x54000010, 64, 5, 19, 1, 4, 0, 0, bra /* BC.cond */},
+{ 0xFFFFFC1F, 0xD61F0000, 64, 0, 0, 0, 0, 0, 0, bra /* BR */},
+{ 0xFEFFF800, 0xD61F0800, 64, 0, 0, 0, 0, 0, 0, bra /* BRA */},
+{ 0x7E000000, 0x34000000, 31, 5, 19, 1, 4, 0, 0, bra /* CBZ/CBNZ */},
+{ 0x7E000000, 0x36000000, 31, 5, 14, 1, 4, 0, 0, bra /* TBZ/TBNZ */},
+{ 0xFC000000, 0x94000000, 64, 0, 26, 1, 4, 0, 0, call /* BL */},
+{ 0xFFFFFC1F, 0xD63F0000, 64, 0, 0, 0, 0, 0, 0, call /* BLR */},
+{ 0xFEFFF800, 0xD63F0800, 64, 0, 0, 0, 0, 0, 0, call /* BLRA */},
+{ 0xFFFFFC1F, 0xD65F0000, 64, 0, 0, 0, 0, 0, 0, ret /* RET */},
+{ 0xFFFFFBFF, 0xD65F0BFF, 64, 0, 0, 0, 0, 0, 0, ret /* RETA */},
+{ 0xFFFFFFFF, 0xD69F03E0, 64, 0, 0, 0, 0, 0, 0, ret /* ERET */},
+{ 0xFFFFFBFF, 0xD69F0BFF, 64, 0, 0, 0, 0, 0, 0, ret /* ERETA */},
+{ 0xFFE00000, 0xD4200000, 64, 5, 16, 0, 1, 0, 0, bug /* BRK */},
+{ 0xFFFFFFFF, 0xD503233F, 64, 0, 0, 0, 1, 0, 0, pac /* PACIASP */},
+};
+unsigned int ndecode = ARRAY_SIZE(decode_array);
+
+static void ignore(struct decode_var *var)
+{
+}
+
+static void check_target(struct decode_var *var)
+{
+ unsigned int rd = var->insn & 0x1F;
+
+ check_reg(rd, var);
+}
+
+struct class class_array[] = {
+/*
+ * mask Class OP mask
+ * opcode Class OP code
+ * check Function to perform checks
+ *
+ * ========================== INSTRUCTION CLASSES =============================
+ * mask opcode check
+ * ============================================================================
+ */
+{ 0x1E000000, 0x00000000, ignore /* RSVD_00 */ },
+{ 0x1E000000, 0x02000000, ignore /* UNALLOC_01 */ },
+{ 0x1E000000, 0x04000000, ignore /* SVE_02 */ },
+{ 0x1E000000, 0x06000000, ignore /* UNALLOC_03 */ },
+{ 0x1E000000, 0x08000000, check_target /* LOAD_STORE_04 */ },
+{ 0x1E000000, 0x0A000000, check_target /* DP_REGISTER_05 */ },
+{ 0x1E000000, 0x0C000000, ignore /* LOAD_STORE_06 */ },
+{ 0x1E000000, 0x0E000000, ignore /* SIMD_FP_07 */ },
+{ 0x1E000000, 0x12000000, check_target /* DP_IMMEDIATE_09 */ },
+{ 0x1E000000, 0x10000000, check_target /* DP_IMMEDIATE_08 */ },
+{ 0x1E000000, 0x14000000, check_target /* BR_SYS_10 */ },
+{ 0x1E000000, 0x16000000, check_target /* BR_SYS_11 */ },
+{ 0x1E000000, 0x18000000, check_target /* LOAD_STORE_12 */ },
+{ 0x1E000000, 0x1A000000, ignore /* DP_REGISTER_13 */ },
+{ 0x1E000000, 0x1C000000, check_target /* LOAD_STORE_14 */ },
+{ 0x1E000000, 0x1E000000, ignore /* SIMD_FP_15 */ },
+};
+unsigned int nclass = ARRAY_SIZE(class_array);
+
+static inline s64 sign_extend(s64 imm, unsigned int bits)
+{
+ return (imm << (64 - bits)) >> (64 - bits);
+}
int arch_decode_instruction(struct objtool_file *file,
const struct section *sec,
unsigned long offset, unsigned int maxlen,
unsigned int *len, enum insn_type *type,
unsigned long *immediate,
- struct list_head *ops_list)
+ struct list_head *ops)
{
+ struct decode *decode;
+ struct decode_var var;
+ struct class *class;
+ unsigned int width, mask, mult, i;
+
+ if (maxlen < INSN_SIZE)
+ return -1;
+ *len = INSN_SIZE;
+
+ var.insn = *(u32 *)(sec->data->d_buf + offset);
+ var.type = INSN_OTHER;
+ var.imm = 0;
+ var.ops = ops;
+
+ *type = INSN_OTHER;
+
+ /* Decode the instruction, if listed. */
+ for (i = 0; i < ndecode; i++) {
+ decode = &decode_array[i];
+
+ if ((var.insn & decode->opmask) != decode->op)
+ continue;
+
+ /* Extract addressing mode (for some instructions). */
+ var.mode1 = 0;
+ var.mode2 = 0;
+ if (decode->mode1)
+ var.mode1 = (var.insn >> decode->mode1) & 1;
+ if (decode->mode2)
+ var.mode2 = (var.insn >> decode->mode2) & 1;
+
+ /* Determine target register width. */
+ width = decode->width;
+ if (width < 0)
+ width = (var.insn & (1 << -width)) ? 32 : 64;
+ else if (width < 32)
+ width = (var.insn & (1 << width)) ? 64 : 32;
+
+ /*
+ * If the target register width is 32 bits, set the check flag
+ * so that the target registers are checked to make sure they
+ * are not the FP or the RA. We should not be using 32-bit
+ * values in these registers.
+ */
+ var.check_reg = (width == 32);
+
+ /* Extract the immediate value. */
+ mask = (1 << decode->bits) - 1;
+ var.imm = (var.insn >> decode->shift) & mask;
+ if (decode->sign_extend)
+ var.imm = sign_extend(var.imm, decode->bits);
+
+ /* Scale the immediate value. */
+ mult = decode->mult;
+ if (!mult)
+ mult = (width == 32) ? 4 : 8;
+ var.imm *= mult;
+
+ /* Decode the instruction. */
+ decode->func(decode, &var);
+ goto out;
+ }
+
+ /*
+ * Sanity check to make sure that the compiler has not generated
+ * code that modifies the FP or the RA in an unexpected way.
+ */
+ for (i = 0; i < nclass; i++) {
+ class = &class_array[i];
+ if ((var.insn & class->opmask) == class->op) {
+ class->check(&var);
+ goto out;
+ }
+ }
+out:
+ *immediate = var.imm;
+ *type = var.type;
return 0;
}
diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/objtool/arch.h
index beb2f3aa94ff..3c2f8c1b8265 100644
--- a/tools/objtool/include/objtool/arch.h
+++ b/tools/objtool/include/objtool/arch.h
@@ -29,6 +29,8 @@ enum insn_type {
INSN_TRAP,
INSN_ENDBR,
INSN_OTHER,
+ INSN_START,
+ INSN_UNRELIABLE,
};
enum op_dest_type {
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2023-02-02 7:42 UTC|newest]
Thread overview: 110+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <0337266cf19f4c98388e3f6d09f590d9de258dc7>
2023-02-02 7:40 ` [RFC PATCH v3 00/22] arm64: livepatch: Use ORC for dynamic frame pointer validation madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 01/22] objtool: Reorganize CFI code madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 02/22] objtool: Reorganize instruction-related code madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 03/22] objtool: Move decode_instructions() to a separate file madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 04/22] objtool: Reorganize Unwind hint code madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 05/22] objtool: Reorganize ORC types madvenka
2023-02-02 7:40 ` madvenka
2023-02-18 9:30 ` Suraj Jitindar Singh
2023-02-18 9:30 ` Suraj Jitindar Singh
2023-03-06 16:45 ` Madhavan T. Venkataraman
2023-03-06 16:45 ` Madhavan T. Venkataraman
2023-02-02 7:40 ` [RFC PATCH v3 06/22] objtool: Reorganize ORC code madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 07/22] objtool: Reorganize ORC kernel code madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 08/22] objtool: Introduce STATIC_CHECK madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 09/22] objtool: arm64: Add basic definitions and compile madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` madvenka [this message]
2023-02-02 7:40 ` [RFC PATCH v3 10/22] objtool: arm64: Implement decoder for Dynamic FP validation madvenka
2023-02-02 7:40 ` [RFC PATCH v3 11/22] objtool: arm64: Invoke the decoder madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 12/22] objtool: arm64: Compute destinations for call and jump instructions madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 13/22] objtool: arm64: Walk instructions and compute CFI for each instruction madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 14/22] objtool: arm64: Generate ORC data from CFI for object files madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 15/22] objtool: arm64: Add unwind hint support madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 16/22] arm64: Add unwind hints to exception handlers madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 17/22] arm64: Add kernel and module support for ORC madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 18/22] arm64: Build the kernel with ORC information madvenka
2023-02-02 7:40 ` madvenka
2023-02-10 7:52 ` Tomohiro Misono (Fujitsu)
2023-02-10 7:52 ` Tomohiro Misono (Fujitsu)
2023-02-11 4:34 ` Madhavan T. Venkataraman
2023-02-11 4:34 ` Madhavan T. Venkataraman
2023-02-02 7:40 ` [RFC PATCH v3 19/22] arm64: unwinder: Add a reliability check in the unwinder based on ORC madvenka
2023-02-02 7:40 ` madvenka
2023-02-23 4:07 ` Suraj Jitindar Singh
2023-02-23 4:07 ` Suraj Jitindar Singh
2023-03-06 16:52 ` Madhavan T. Venkataraman
2023-03-06 16:52 ` Madhavan T. Venkataraman
2023-02-02 7:40 ` [RFC PATCH v3 20/22] arm64: Define HAVE_DYNAMIC_FTRACE_WITH_ARGS madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 21/22] arm64: Define TIF_PATCH_PENDING for livepatch madvenka
2023-02-02 7:40 ` madvenka
2023-02-02 7:40 ` [RFC PATCH v3 22/22] arm64: Enable livepatch for ARM64 madvenka
2023-02-02 7:40 ` madvenka
2023-03-01 3:12 ` [RFC PATCH v3 00/22] arm64: livepatch: Use ORC for dynamic frame pointer validation Tomohiro Misono (Fujitsu)
2023-03-01 3:12 ` Tomohiro Misono (Fujitsu)
2023-03-02 16:23 ` Petr Mladek
2023-03-02 16:23 ` Petr Mladek
2023-03-03 9:40 ` Tomohiro Misono (Fujitsu)
2023-03-03 9:40 ` Tomohiro Misono (Fujitsu)
2023-03-06 16:58 ` Madhavan T. Venkataraman
2023-03-06 16:58 ` Madhavan T. Venkataraman
2023-03-06 16:57 ` Madhavan T. Venkataraman
2023-03-06 16:57 ` Madhavan T. Venkataraman
2023-03-23 17:17 ` Mark Rutland
2023-03-23 17:17 ` Mark Rutland
2023-04-08 3:40 ` Madhavan T. Venkataraman
2023-04-08 3:40 ` Madhavan T. Venkataraman
2023-04-11 13:25 ` Mark Rutland
2023-04-11 13:25 ` Mark Rutland
2023-04-12 4:17 ` Josh Poimboeuf
2023-04-12 4:17 ` Josh Poimboeuf
2023-04-12 4:48 ` Madhavan T. Venkataraman
2023-04-12 4:48 ` Madhavan T. Venkataraman
2023-04-12 4:50 ` Madhavan T. Venkataraman
2023-04-12 4:50 ` Madhavan T. Venkataraman
2023-04-12 5:01 ` Josh Poimboeuf
2023-04-12 5:01 ` Josh Poimboeuf
2023-04-12 14:50 ` Madhavan T. Venkataraman
2023-04-12 14:50 ` Madhavan T. Venkataraman
2023-04-12 15:52 ` Josh Poimboeuf
2023-04-12 15:52 ` Josh Poimboeuf
2023-04-13 14:59 ` Madhavan T. Venkataraman
2023-04-13 14:59 ` Madhavan T. Venkataraman
2023-04-13 16:30 ` Josh Poimboeuf
2023-04-13 16:30 ` Josh Poimboeuf
2023-04-15 4:27 ` Madhavan T. Venkataraman
2023-04-15 4:27 ` Madhavan T. Venkataraman
2023-04-15 5:05 ` Josh Poimboeuf
2023-04-15 5:05 ` Josh Poimboeuf
2023-04-15 16:15 ` Madhavan T. Venkataraman
2023-04-15 16:15 ` Madhavan T. Venkataraman
2023-04-16 8:21 ` Indu Bhagat
2023-04-16 8:21 ` Indu Bhagat
2023-04-13 17:04 ` Nick Desaulniers
2023-04-13 17:04 ` Nick Desaulniers
2023-04-13 18:15 ` Jose E. Marchesi
2023-04-13 18:15 ` Jose E. Marchesi
2023-04-15 4:14 ` Madhavan T. Venkataraman
2023-04-15 4:14 ` Madhavan T. Venkataraman
2023-12-14 20:49 ` ARM64 Livepatch based on SFrame Madhavan T. Venkataraman
2023-12-14 20:49 ` Madhavan T. Venkataraman
2023-12-15 13:04 ` Mark Rutland
2023-12-15 13:04 ` Mark Rutland
2023-12-15 15:15 ` Madhavan T. Venkataraman
2023-12-15 15:15 ` Madhavan T. Venkataraman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230202074036.507249-11-madvenka@linux.microsoft.com \
--to=madvenka@linux.microsoft.com \
--cc=broonie@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=chenzhongjin@huawei.com \
--cc=jamorris@linux.microsoft.com \
--cc=jpoimboe@redhat.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=live-patching@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=nobuta.keiya@fujitsu.com \
--cc=peterz@infradead.org \
--cc=sjitindarsingh@gmail.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.