diff options
Diffstat (limited to 'tools/objtool/arch')
-rw-r--r-- | tools/objtool/arch/x86/decode.c | 91 |
1 files changed, 40 insertions, 51 deletions
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index a36c2eba64e7..0e8c8ec4fd4e 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -86,8 +86,8 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, struct insn insn; int x86_64, sign; unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, - modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0, - sib = 0; + rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0, + modrm_reg = 0, sib = 0; x86_64 = is_x86_64(elf); if (x86_64 == -1) @@ -114,6 +114,7 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, rex = insn.rex_prefix.bytes[0]; rex_w = X86_REX_W(rex) >> 3; rex_r = X86_REX_R(rex) >> 2; + rex_x = X86_REX_X(rex) >> 1; rex_b = X86_REX_B(rex); } @@ -217,6 +218,18 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, op->dest.reg = CFI_BP; break; } + + if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) { + + /* mov reg, %rsp */ + *type = INSN_STACK; + op->src.type = OP_SRC_REG; + op->src.reg = op_to_cfi_reg[modrm_reg][rex_r]; + op->dest.type = OP_DEST_REG; + op->dest.reg = CFI_SP; + break; + } + /* fallthrough */ case 0x88: if (!rex_b && @@ -269,56 +282,28 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, break; case 0x8d: - if (rex == 0x48 && modrm == 0x65) { + if (sib == 0x24 && rex_w && !rex_b && !rex_x) { - /* lea -disp(%rbp), %rsp */ - *type = INSN_STACK; - op->src.type = OP_SRC_ADD; - op->src.reg = CFI_BP; - op->src.offset = insn.displacement.value; - op->dest.type = OP_DEST_REG; - op->dest.reg = CFI_SP; - break; - } - - if (rex == 0x4c && modrm == 0x54 && sib == 0x24 && - insn.displacement.value == 8) { - - /* - * lea 0x8(%rsp), %r10 - * - * Here r10 is the "drap" pointer, used as a stack - * pointer helper when the stack gets realigned. - */ + /* lea disp(%rsp), reg */ *type = INSN_STACK; op->src.type = OP_SRC_ADD; op->src.reg = CFI_SP; - op->src.offset = 8; + op->src.offset = insn.displacement.value; op->dest.type = OP_DEST_REG; - op->dest.reg = CFI_R10; - break; - } + op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r]; - if (rex == 0x4c && modrm == 0x6c && sib == 0x24 && - insn.displacement.value == 16) { + } else if (rex == 0x48 && modrm == 0x65) { - /* - * lea 0x10(%rsp), %r13 - * - * Here r13 is the "drap" pointer, used as a stack - * pointer helper when the stack gets realigned. - */ + /* lea disp(%rbp), %rsp */ *type = INSN_STACK; op->src.type = OP_SRC_ADD; - op->src.reg = CFI_SP; - op->src.offset = 16; + op->src.reg = CFI_BP; + op->src.offset = insn.displacement.value; op->dest.type = OP_DEST_REG; - op->dest.reg = CFI_R13; - break; - } + op->dest.reg = CFI_SP; - if (rex == 0x49 && modrm == 0x62 && - insn.displacement.value == -8) { + } else if (rex == 0x49 && modrm == 0x62 && + insn.displacement.value == -8) { /* * lea -0x8(%r10), %rsp @@ -332,11 +317,9 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, op->src.offset = -8; op->dest.type = OP_DEST_REG; op->dest.reg = CFI_SP; - break; - } - if (rex == 0x49 && modrm == 0x65 && - insn.displacement.value == -16) { + } else if (rex == 0x49 && modrm == 0x65 && + insn.displacement.value == -16) { /* * lea -0x10(%r13), %rsp @@ -350,7 +333,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, op->src.offset = -16; op->dest.type = OP_DEST_REG; op->dest.reg = CFI_SP; - break; } break; @@ -382,20 +364,27 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, case 0x0f: - if (op2 >= 0x80 && op2 <= 0x8f) + if (op2 >= 0x80 && op2 <= 0x8f) { + *type = INSN_JUMP_CONDITIONAL; - else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || - op2 == 0x35) + + } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || + op2 == 0x35) { /* sysenter, sysret */ *type = INSN_CONTEXT_SWITCH; - else if (op2 == 0x0d || op2 == 0x1f) + } else if (op2 == 0x0b || op2 == 0xb9) { + + /* ud2 */ + *type = INSN_BUG; + + } else if (op2 == 0x0d || op2 == 0x1f) { /* nopl/nopw */ *type = INSN_NOP; - else if (op2 == 0xa0 || op2 == 0xa8) { + } else if (op2 == 0xa0 || op2 == 0xa8) { /* push fs/gs */ *type = INSN_STACK; |