]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - tools/objtool/arch/x86/decode.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
9 #define unlikely(cond) (cond)
11 #include "../../../arch/x86/lib/inat.c"
12 #include "../../../arch/x86/lib/insn.c"
14 #define CONFIG_64BIT 1
17 #include <asm/orc_types.h>
18 #include <objtool/check.h>
19 #include <objtool/elf.h>
20 #include <objtool/arch.h>
21 #include <objtool/warn.h>
22 #include <objtool/endianness.h>
25 static int is_x86_64(const struct elf
*elf
)
27 switch (elf
->ehdr
.e_machine
) {
33 WARN("unexpected ELF machine type %d", elf
->ehdr
.e_machine
);
38 bool arch_callee_saved_reg(unsigned char reg
)
65 unsigned long arch_dest_reloc_offset(int addend
)
70 unsigned long arch_jump_destination(struct instruction
*insn
)
72 return insn
->offset
+ insn
->len
+ insn
->immediate
;
76 if (!(op = calloc(1, sizeof(*op)))) \
78 else for (list_add_tail(&op->list, ops_list); op; op = NULL)
81 * Helpers to decode ModRM/SIB:
83 * r/m| AX CX DX BX | SP | BP | SI DI |
84 * | R8 R9 R10 R11 | R12 | R13 | R14 R15 |
85 * Mod+----------------+-----+-----+---------+
86 * 00 | [r/m] |[SIB]|[IP+]| [r/m] |
87 * 01 | [r/m + d8] |[S+d]| [r/m + d8] |
88 * 10 | [r/m + d32] |[S+D]| [r/m + d32] |
92 #define mod_is_mem() (modrm_mod != 3)
93 #define mod_is_reg() (modrm_mod == 3)
95 #define is_RIP() ((modrm_rm & 7) == CFI_BP && modrm_mod == 0)
96 #define have_SIB() ((modrm_rm & 7) == CFI_SP && mod_is_mem())
98 #define rm_is(reg) (have_SIB() ? \
99 sib_base == (reg) && sib_index == CFI_SP : \
102 #define rm_is_mem(reg) (mod_is_mem() && !is_RIP() && rm_is(reg))
103 #define rm_is_reg(reg) (mod_is_reg() && modrm_rm == (reg))
105 int arch_decode_instruction(const struct elf
*elf
, const struct section
*sec
,
106 unsigned long offset
, unsigned int maxlen
,
107 unsigned int *len
, enum insn_type
*type
,
108 unsigned long *immediate
,
109 struct list_head
*ops_list
)
113 unsigned char op1
, op2
,
114 rex
= 0, rex_b
= 0, rex_r
= 0, rex_w
= 0, rex_x
= 0,
115 modrm
= 0, modrm_mod
= 0, modrm_rm
= 0, modrm_reg
= 0,
116 sib
= 0, /* sib_scale = 0, */ sib_index
= 0, sib_base
= 0;
117 struct stack_op
*op
= NULL
;
121 x86_64
= is_x86_64(elf
);
125 ret
= insn_decode(&insn
, sec
->data
->d_buf
+ offset
, maxlen
,
126 x86_64
? INSN_MODE_64
: INSN_MODE_32
);
128 WARN("can't decode instruction at %s:0x%lx", sec
->name
, offset
);
135 if (insn
.vex_prefix
.nbytes
)
138 op1
= insn
.opcode
.bytes
[0];
139 op2
= insn
.opcode
.bytes
[1];
141 if (insn
.rex_prefix
.nbytes
) {
142 rex
= insn
.rex_prefix
.bytes
[0];
143 rex_w
= X86_REX_W(rex
) >> 3;
144 rex_r
= X86_REX_R(rex
) >> 2;
145 rex_x
= X86_REX_X(rex
) >> 1;
146 rex_b
= X86_REX_B(rex
);
149 if (insn
.modrm
.nbytes
) {
150 modrm
= insn
.modrm
.bytes
[0];
151 modrm_mod
= X86_MODRM_MOD(modrm
);
152 modrm_reg
= X86_MODRM_REG(modrm
) + 8*rex_r
;
153 modrm_rm
= X86_MODRM_RM(modrm
) + 8*rex_b
;
156 if (insn
.sib
.nbytes
) {
157 sib
= insn
.sib
.bytes
[0];
158 /* sib_scale = X86_SIB_SCALE(sib); */
159 sib_index
= X86_SIB_INDEX(sib
) + 8*rex_x
;
160 sib_base
= X86_SIB_BASE(sib
) + 8*rex_b
;
167 if (rex_w
&& rm_is_reg(CFI_SP
)) {
169 /* add/sub reg, %rsp */
171 op
->src
.type
= OP_SRC_ADD
;
172 op
->src
.reg
= modrm_reg
;
173 op
->dest
.type
= OP_DEST_REG
;
174 op
->dest
.reg
= CFI_SP
;
183 op
->src
.type
= OP_SRC_REG
;
184 op
->src
.reg
= (op1
& 0x7) + 8*rex_b
;
185 op
->dest
.type
= OP_DEST_PUSH
;
194 op
->src
.type
= OP_SRC_POP
;
195 op
->dest
.type
= OP_DEST_REG
;
196 op
->dest
.reg
= (op1
& 0x7) + 8*rex_b
;
205 op
->src
.type
= OP_SRC_CONST
;
206 op
->dest
.type
= OP_DEST_PUSH
;
211 *type
= INSN_JUMP_CONDITIONAL
;
216 * 1000 00sw : mod OP r/m : immediate
218 * s - sign extend immediate
221 * OP: 000 ADD 100 AND
231 /* %rsp target only */
232 if (!rm_is_reg(CFI_SP
))
235 imm
= insn
.immediate
.value
;
236 if (op1
& 2) { /* sign extend */
237 if (op1
& 1) { /* imm32 */
239 imm
= (s64
)imm
>> 32;
242 imm
= (s64
)imm
>> 56;
246 switch (modrm_reg
& 7) {
251 /* add/sub imm, %rsp */
253 op
->src
.type
= OP_SRC_ADD
;
254 op
->src
.reg
= CFI_SP
;
255 op
->src
.offset
= imm
;
256 op
->dest
.type
= OP_DEST_REG
;
257 op
->dest
.reg
= CFI_SP
;
264 op
->src
.type
= OP_SRC_AND
;
265 op
->src
.reg
= CFI_SP
;
266 op
->src
.offset
= insn
.immediate
.value
;
267 op
->dest
.type
= OP_DEST_REG
;
268 op
->dest
.reg
= CFI_SP
;
283 if (modrm_reg
== CFI_SP
) {
288 op
->src
.type
= OP_SRC_REG
;
289 op
->src
.reg
= CFI_SP
;
290 op
->dest
.type
= OP_DEST_REG
;
291 op
->dest
.reg
= modrm_rm
;
296 /* skip RIP relative displacement */
300 /* skip nontrivial SIB */
303 if (sib_index
!= CFI_SP
)
307 /* mov %rsp, disp(%reg) */
309 op
->src
.type
= OP_SRC_REG
;
310 op
->src
.reg
= CFI_SP
;
311 op
->dest
.type
= OP_DEST_REG_INDIRECT
;
312 op
->dest
.reg
= modrm_rm
;
313 op
->dest
.offset
= insn
.displacement
.value
;
321 if (rm_is_reg(CFI_SP
)) {
325 op
->src
.type
= OP_SRC_REG
;
326 op
->src
.reg
= modrm_reg
;
327 op
->dest
.type
= OP_DEST_REG
;
328 op
->dest
.reg
= CFI_SP
;
338 if (rm_is_mem(CFI_BP
)) {
340 /* mov reg, disp(%rbp) */
342 op
->src
.type
= OP_SRC_REG
;
343 op
->src
.reg
= modrm_reg
;
344 op
->dest
.type
= OP_DEST_REG_INDIRECT
;
345 op
->dest
.reg
= CFI_BP
;
346 op
->dest
.offset
= insn
.displacement
.value
;
351 if (rm_is_mem(CFI_SP
)) {
353 /* mov reg, disp(%rsp) */
355 op
->src
.type
= OP_SRC_REG
;
356 op
->src
.reg
= modrm_reg
;
357 op
->dest
.type
= OP_DEST_REG_INDIRECT
;
358 op
->dest
.reg
= CFI_SP
;
359 op
->dest
.offset
= insn
.displacement
.value
;
370 if (rm_is_mem(CFI_BP
)) {
372 /* mov disp(%rbp), reg */
374 op
->src
.type
= OP_SRC_REG_INDIRECT
;
375 op
->src
.reg
= CFI_BP
;
376 op
->src
.offset
= insn
.displacement
.value
;
377 op
->dest
.type
= OP_DEST_REG
;
378 op
->dest
.reg
= modrm_reg
;
383 if (rm_is_mem(CFI_SP
)) {
385 /* mov disp(%rsp), reg */
387 op
->src
.type
= OP_SRC_REG_INDIRECT
;
388 op
->src
.reg
= CFI_SP
;
389 op
->src
.offset
= insn
.displacement
.value
;
390 op
->dest
.type
= OP_DEST_REG
;
391 op
->dest
.reg
= modrm_reg
;
400 WARN("invalid LEA encoding at %s:0x%lx", sec
->name
, offset
);
404 /* skip non 64bit ops */
408 /* skip RIP relative displacement */
412 /* skip nontrivial SIB */
415 if (sib_index
!= CFI_SP
)
419 /* lea disp(%src), %dst */
421 op
->src
.offset
= insn
.displacement
.value
;
422 if (!op
->src
.offset
) {
423 /* lea (%src), %dst */
424 op
->src
.type
= OP_SRC_REG
;
426 /* lea disp(%src), %dst */
427 op
->src
.type
= OP_SRC_ADD
;
429 op
->src
.reg
= modrm_rm
;
430 op
->dest
.type
= OP_DEST_REG
;
431 op
->dest
.reg
= modrm_reg
;
438 op
->src
.type
= OP_SRC_POP
;
439 op
->dest
.type
= OP_DEST_MEM
;
450 op
->src
.type
= OP_SRC_CONST
;
451 op
->dest
.type
= OP_DEST_PUSHF
;
458 op
->src
.type
= OP_SRC_POPF
;
459 op
->dest
.type
= OP_DEST_MEM
;
469 else if (modrm
== 0xcb)
472 } else if (op2
>= 0x80 && op2
<= 0x8f) {
474 *type
= INSN_JUMP_CONDITIONAL
;
476 } else if (op2
== 0x05 || op2
== 0x07 || op2
== 0x34 ||
479 /* sysenter, sysret */
480 *type
= INSN_CONTEXT_SWITCH
;
482 } else if (op2
== 0x0b || op2
== 0xb9) {
487 } else if (op2
== 0x0d || op2
== 0x1f) {
492 } else if (op2
== 0xa0 || op2
== 0xa8) {
496 op
->src
.type
= OP_SRC_CONST
;
497 op
->dest
.type
= OP_DEST_PUSH
;
500 } else if (op2
== 0xa1 || op2
== 0xa9) {
504 op
->src
.type
= OP_SRC_POP
;
505 op
->dest
.type
= OP_DEST_MEM
;
520 op
->src
.type
= OP_SRC_REG
;
521 op
->src
.reg
= CFI_BP
;
522 op
->dest
.type
= OP_DEST_REG
;
523 op
->dest
.reg
= CFI_SP
;
526 op
->src
.type
= OP_SRC_POP
;
527 op
->dest
.type
= OP_DEST_REG
;
528 op
->dest
.reg
= CFI_BP
;
539 *type
= INSN_JUMP_CONDITIONAL
;
544 *type
= INSN_JUMP_UNCONDITIONAL
;
552 case 0xcf: /* iret */
554 * Handle sync_core(), which has an IRET to self.
555 * All other IRET are in STT_NONE entry code.
557 sym
= find_symbol_containing(sec
, offset
);
558 if (sym
&& sym
->type
== STT_FUNC
) {
561 op
->src
.type
= OP_SRC_ADD
;
562 op
->src
.reg
= CFI_SP
;
563 op
->src
.offset
= 5*8;
564 op
->dest
.type
= OP_DEST_REG
;
565 op
->dest
.reg
= CFI_SP
;
572 case 0xca: /* retf */
573 case 0xcb: /* retf */
574 *type
= INSN_CONTEXT_SWITCH
;
580 * For the impact on the stack, a CALL behaves like
581 * a PUSH of an immediate value (the return address).
584 op
->src
.type
= OP_SRC_CONST
;
585 op
->dest
.type
= OP_DEST_PUSH
;
598 if (modrm_reg
== 2 || modrm_reg
== 3)
600 *type
= INSN_CALL_DYNAMIC
;
602 else if (modrm_reg
== 4)
604 *type
= INSN_JUMP_DYNAMIC
;
606 else if (modrm_reg
== 5)
609 *type
= INSN_CONTEXT_SWITCH
;
611 else if (modrm_reg
== 6) {
615 op
->src
.type
= OP_SRC_CONST
;
616 op
->dest
.type
= OP_DEST_PUSH
;
626 *immediate
= insn
.immediate
.nbytes
? insn
.immediate
.value
: 0;
631 void arch_initial_func_cfi_state(struct cfi_init_state
*state
)
635 for (i
= 0; i
< CFI_NUM_REGS
; i
++) {
636 state
->regs
[i
].base
= CFI_UNDEFINED
;
637 state
->regs
[i
].offset
= 0;
640 /* initial CFA (call frame address) */
641 state
->cfa
.base
= CFI_SP
;
642 state
->cfa
.offset
= 8;
644 /* initial RA (return address) */
645 state
->regs
[CFI_RA
].base
= CFI_CFA
;
646 state
->regs
[CFI_RA
].offset
= -8;
649 const char *arch_nop_insn(int len
)
651 static const char nops
[5][5] = {
659 if (len
< 1 || len
> 5) {
660 WARN("invalid NOP size: %d\n", len
);
667 #define BYTE_RET 0xC3
669 const char *arch_ret_insn(int len
)
671 static const char ret
[5][5] = {
674 { BYTE_RET
, 0xcc, BYTES_NOP1
},
675 { BYTE_RET
, 0xcc, BYTES_NOP2
},
676 { BYTE_RET
, 0xcc, BYTES_NOP3
},
679 if (len
< 1 || len
> 5) {
680 WARN("invalid RET size: %d\n", len
);
687 int arch_decode_hint_reg(u8 sp_reg
, int *base
)
690 case ORC_REG_UNDEFINED
:
691 *base
= CFI_UNDEFINED
;
699 case ORC_REG_SP_INDIRECT
:
700 *base
= CFI_SP_INDIRECT
;
721 bool arch_is_retpoline(struct symbol
*sym
)
723 return !strncmp(sym
->name
, "__x86_indirect_", 15);
726 bool arch_is_rethunk(struct symbol
*sym
)
728 return !strcmp(sym
->name
, "__x86_return_thunk");