xref: /openbmc/linux/tools/objtool/arch/x86/decode.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2442f04c3SJosh Poimboeuf /*
3442f04c3SJosh Poimboeuf  * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
4442f04c3SJosh Poimboeuf  */
5442f04c3SJosh Poimboeuf 
6442f04c3SJosh Poimboeuf #include <stdio.h>
7442f04c3SJosh Poimboeuf #include <stdlib.h>
8442f04c3SJosh Poimboeuf 
9442f04c3SJosh Poimboeuf #define unlikely(cond) (cond)
106a77cff8SJosh Poimboeuf #include <asm/insn.h>
11d046b725SJosh Poimboeuf #include "../../../arch/x86/lib/inat.c"
12d046b725SJosh Poimboeuf #include "../../../arch/x86/lib/insn.c"
13442f04c3SJosh Poimboeuf 
14301cddc2SPeter Zijlstra #define CONFIG_64BIT 1
15301cddc2SPeter Zijlstra #include <asm/nops.h>
16301cddc2SPeter Zijlstra 
17edea9e6bSJulien Thierry #include <asm/orc_types.h>
187786032eSVasily Gorbik #include <objtool/check.h>
197786032eSVasily Gorbik #include <objtool/elf.h>
207786032eSVasily Gorbik #include <objtool/arch.h>
217786032eSVasily Gorbik #include <objtool/warn.h>
22f66c05d6SVasily Gorbik #include <objtool/endianness.h>
23db2b0c5dSPeter Zijlstra #include <objtool/builtin.h>
249bc0bb50SPeter Zijlstra #include <arch/elf.h>
25442f04c3SJosh Poimboeuf 
arch_ftrace_match(char * name)264ca993d4SSathvika Vasireddy int arch_ftrace_match(char *name)
274ca993d4SSathvika Vasireddy {
284ca993d4SSathvika Vasireddy 	return !strcmp(name, "__fentry__");
294ca993d4SSathvika Vasireddy }
304ca993d4SSathvika Vasireddy 
is_x86_64(const struct elf * elf)310c98be81SIngo Molnar static int is_x86_64(const struct elf *elf)
32442f04c3SJosh Poimboeuf {
33442f04c3SJosh Poimboeuf 	switch (elf->ehdr.e_machine) {
34442f04c3SJosh Poimboeuf 	case EM_X86_64:
35442f04c3SJosh Poimboeuf 		return 1;
36442f04c3SJosh Poimboeuf 	case EM_386:
37442f04c3SJosh Poimboeuf 		return 0;
38442f04c3SJosh Poimboeuf 	default:
39442f04c3SJosh Poimboeuf 		WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
40442f04c3SJosh Poimboeuf 		return -1;
41442f04c3SJosh Poimboeuf 	}
42442f04c3SJosh Poimboeuf }
43442f04c3SJosh Poimboeuf 
arch_callee_saved_reg(unsigned char reg)44baa41469SJosh Poimboeuf bool arch_callee_saved_reg(unsigned char reg)
45baa41469SJosh Poimboeuf {
46baa41469SJosh Poimboeuf 	switch (reg) {
47baa41469SJosh Poimboeuf 	case CFI_BP:
48baa41469SJosh Poimboeuf 	case CFI_BX:
49baa41469SJosh Poimboeuf 	case CFI_R12:
50baa41469SJosh Poimboeuf 	case CFI_R13:
51baa41469SJosh Poimboeuf 	case CFI_R14:
52baa41469SJosh Poimboeuf 	case CFI_R15:
53baa41469SJosh Poimboeuf 		return true;
54baa41469SJosh Poimboeuf 
55baa41469SJosh Poimboeuf 	case CFI_AX:
56baa41469SJosh Poimboeuf 	case CFI_CX:
57baa41469SJosh Poimboeuf 	case CFI_DX:
58baa41469SJosh Poimboeuf 	case CFI_SI:
59baa41469SJosh Poimboeuf 	case CFI_DI:
60baa41469SJosh Poimboeuf 	case CFI_SP:
61baa41469SJosh Poimboeuf 	case CFI_R8:
62baa41469SJosh Poimboeuf 	case CFI_R9:
63baa41469SJosh Poimboeuf 	case CFI_R10:
64baa41469SJosh Poimboeuf 	case CFI_R11:
65baa41469SJosh Poimboeuf 	case CFI_RA:
66baa41469SJosh Poimboeuf 	default:
67baa41469SJosh Poimboeuf 		return false;
68baa41469SJosh Poimboeuf 	}
69baa41469SJosh Poimboeuf }
70baa41469SJosh Poimboeuf 
arch_dest_reloc_offset(int addend)71f1974222SMatt Helsley unsigned long arch_dest_reloc_offset(int addend)
72bfb08f22SRaphael Gault {
73bfb08f22SRaphael Gault 	return addend + 4;
74bfb08f22SRaphael Gault }
75bfb08f22SRaphael Gault 
arch_jump_destination(struct instruction * insn)76bfb08f22SRaphael Gault unsigned long arch_jump_destination(struct instruction *insn)
77bfb08f22SRaphael Gault {
78bfb08f22SRaphael Gault 	return insn->offset + insn->len + insn->immediate;
79bfb08f22SRaphael Gault }
80bfb08f22SRaphael Gault 
arch_pc_relative_reloc(struct reloc * reloc)8161c6065eSPeter Zijlstra bool arch_pc_relative_reloc(struct reloc *reloc)
8261c6065eSPeter Zijlstra {
8361c6065eSPeter Zijlstra 	/*
8461c6065eSPeter Zijlstra 	 * All relocation types where P (the address of the target)
8561c6065eSPeter Zijlstra 	 * is included in the computation.
8661c6065eSPeter Zijlstra 	 */
87fcee899dSJosh Poimboeuf 	switch (reloc_type(reloc)) {
8861c6065eSPeter Zijlstra 	case R_X86_64_PC8:
8961c6065eSPeter Zijlstra 	case R_X86_64_PC16:
9061c6065eSPeter Zijlstra 	case R_X86_64_PC32:
9161c6065eSPeter Zijlstra 	case R_X86_64_PC64:
9261c6065eSPeter Zijlstra 
9361c6065eSPeter Zijlstra 	case R_X86_64_PLT32:
9461c6065eSPeter Zijlstra 	case R_X86_64_GOTPC32:
9561c6065eSPeter Zijlstra 	case R_X86_64_GOTPCREL:
9661c6065eSPeter Zijlstra 		return true;
9761c6065eSPeter Zijlstra 
9861c6065eSPeter Zijlstra 	default:
9961c6065eSPeter Zijlstra 		break;
10061c6065eSPeter Zijlstra 	}
10161c6065eSPeter Zijlstra 
10261c6065eSPeter Zijlstra 	return false;
10361c6065eSPeter Zijlstra }
10461c6065eSPeter Zijlstra 
1057d989fcaSPeter Zijlstra #define ADD_OP(op) \
1067d989fcaSPeter Zijlstra 	if (!(op = calloc(1, sizeof(*op)))) \
1077d989fcaSPeter Zijlstra 		return -1; \
1083ee88df1SPeter Zijlstra 	else for (*ops_list = op, ops_list = &op->next; op; op = NULL)
1097d989fcaSPeter Zijlstra 
11078df6245SPeter Zijlstra /*
11178df6245SPeter Zijlstra  * Helpers to decode ModRM/SIB:
11278df6245SPeter Zijlstra  *
11378df6245SPeter Zijlstra  * r/m| AX  CX  DX  BX |  SP |  BP |  SI  DI |
11478df6245SPeter Zijlstra  *    | R8  R9 R10 R11 | R12 | R13 | R14 R15 |
11578df6245SPeter Zijlstra  * Mod+----------------+-----+-----+---------+
11678df6245SPeter Zijlstra  * 00 |    [r/m]       |[SIB]|[IP+]|  [r/m]  |
11778df6245SPeter Zijlstra  * 01 |  [r/m + d8]    |[S+d]|   [r/m + d8]  |
11878df6245SPeter Zijlstra  * 10 |  [r/m + d32]   |[S+D]|   [r/m + d32] |
11978df6245SPeter Zijlstra  * 11 |                   r/ m               |
12078df6245SPeter Zijlstra  */
12136d92e43SPeter Zijlstra 
12236d92e43SPeter Zijlstra #define mod_is_mem()	(modrm_mod != 3)
12336d92e43SPeter Zijlstra #define mod_is_reg()	(modrm_mod == 3)
12436d92e43SPeter Zijlstra 
12578df6245SPeter Zijlstra #define is_RIP()   ((modrm_rm & 7) == CFI_BP && modrm_mod == 0)
12636d92e43SPeter Zijlstra #define have_SIB() ((modrm_rm & 7) == CFI_SP && mod_is_mem())
12778df6245SPeter Zijlstra 
12878df6245SPeter Zijlstra #define rm_is(reg) (have_SIB() ? \
12978df6245SPeter Zijlstra 		    sib_base == (reg) && sib_index == CFI_SP : \
13078df6245SPeter Zijlstra 		    modrm_rm == (reg))
13178df6245SPeter Zijlstra 
13236d92e43SPeter Zijlstra #define rm_is_mem(reg)	(mod_is_mem() && !is_RIP() && rm_is(reg))
13336d92e43SPeter Zijlstra #define rm_is_reg(reg)	(mod_is_reg() && modrm_rm == (reg))
13436d92e43SPeter Zijlstra 
has_notrack_prefix(struct insn * insn)1357d209d13SPeter Zijlstra static bool has_notrack_prefix(struct insn *insn)
1367d209d13SPeter Zijlstra {
1377d209d13SPeter Zijlstra 	int i;
1387d209d13SPeter Zijlstra 
1397d209d13SPeter Zijlstra 	for (i = 0; i < insn->prefixes.nbytes; i++) {
1407d209d13SPeter Zijlstra 		if (insn->prefixes.bytes[i] == 0x3e)
1417d209d13SPeter Zijlstra 			return true;
1427d209d13SPeter Zijlstra 	}
1437d209d13SPeter Zijlstra 
1447d209d13SPeter Zijlstra 	return false;
1457d209d13SPeter Zijlstra }
1467d209d13SPeter Zijlstra 
arch_decode_instruction(struct objtool_file * file,const struct section * sec,unsigned long offset,unsigned int maxlen,struct instruction * insn)147db2b0c5dSPeter Zijlstra int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
148442f04c3SJosh Poimboeuf 			    unsigned long offset, unsigned int maxlen,
14920a55463SPeter Zijlstra 			    struct instruction *insn)
150442f04c3SJosh Poimboeuf {
1513ee88df1SPeter Zijlstra 	struct stack_op **ops_list = &insn->stack_ops;
152db2b0c5dSPeter Zijlstra 	const struct elf *elf = file->elf;
15320a55463SPeter Zijlstra 	struct insn ins;
15403b2cd72SLinus Torvalds 	int x86_64, ret;
1557d209d13SPeter Zijlstra 	unsigned char op1, op2, op3, prefix,
1562ee0c363SPeter Zijlstra 		      rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0,
1572ee0c363SPeter Zijlstra 		      modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0,
15878df6245SPeter Zijlstra 		      sib = 0, /* sib_scale = 0, */ sib_index = 0, sib_base = 0;
1597d989fcaSPeter Zijlstra 	struct stack_op *op = NULL;
160b490f453SMiroslav Benes 	struct symbol *sym;
161961d83b9SPeter Zijlstra 	u64 imm;
162442f04c3SJosh Poimboeuf 
163442f04c3SJosh Poimboeuf 	x86_64 = is_x86_64(elf);
164442f04c3SJosh Poimboeuf 	if (x86_64 == -1)
165442f04c3SJosh Poimboeuf 		return -1;
166442f04c3SJosh Poimboeuf 
16720a55463SPeter Zijlstra 	ret = insn_decode(&ins, sec->data->d_buf + offset, maxlen,
168c7e41b09SBorislav Petkov 			  x86_64 ? INSN_MODE_64 : INSN_MODE_32);
169c7e41b09SBorislav Petkov 	if (ret < 0) {
1700c98be81SIngo Molnar 		WARN("can't decode instruction at %s:0x%lx", sec->name, offset);
171442f04c3SJosh Poimboeuf 		return -1;
172442f04c3SJosh Poimboeuf 	}
173442f04c3SJosh Poimboeuf 
17420a55463SPeter Zijlstra 	insn->len = ins.length;
17520a55463SPeter Zijlstra 	insn->type = INSN_OTHER;
176442f04c3SJosh Poimboeuf 
17720a55463SPeter Zijlstra 	if (ins.vex_prefix.nbytes)
178442f04c3SJosh Poimboeuf 		return 0;
179442f04c3SJosh Poimboeuf 
18020a55463SPeter Zijlstra 	prefix = ins.prefixes.bytes[0];
1817d209d13SPeter Zijlstra 
18220a55463SPeter Zijlstra 	op1 = ins.opcode.bytes[0];
18320a55463SPeter Zijlstra 	op2 = ins.opcode.bytes[1];
18420a55463SPeter Zijlstra 	op3 = ins.opcode.bytes[2];
185442f04c3SJosh Poimboeuf 
18620a55463SPeter Zijlstra 	if (ins.rex_prefix.nbytes) {
18720a55463SPeter Zijlstra 		rex = ins.rex_prefix.bytes[0];
188baa41469SJosh Poimboeuf 		rex_w = X86_REX_W(rex) >> 3;
189baa41469SJosh Poimboeuf 		rex_r = X86_REX_R(rex) >> 2;
190dd88a0a0SJosh Poimboeuf 		rex_x = X86_REX_X(rex) >> 1;
191baa41469SJosh Poimboeuf 		rex_b = X86_REX_B(rex);
192baa41469SJosh Poimboeuf 	}
193baa41469SJosh Poimboeuf 
19420a55463SPeter Zijlstra 	if (ins.modrm.nbytes) {
19520a55463SPeter Zijlstra 		modrm = ins.modrm.bytes[0];
196baa41469SJosh Poimboeuf 		modrm_mod = X86_MODRM_MOD(modrm);
19716ef7f15SPeter Zijlstra 		modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r;
19816ef7f15SPeter Zijlstra 		modrm_rm  = X86_MODRM_RM(modrm)  + 8*rex_b;
199baa41469SJosh Poimboeuf 	}
200baa41469SJosh Poimboeuf 
20120a55463SPeter Zijlstra 	if (ins.sib.nbytes) {
20220a55463SPeter Zijlstra 		sib = ins.sib.bytes[0];
20378df6245SPeter Zijlstra 		/* sib_scale = X86_SIB_SCALE(sib); */
20416ef7f15SPeter Zijlstra 		sib_index = X86_SIB_INDEX(sib) + 8*rex_x;
20516ef7f15SPeter Zijlstra 		sib_base  = X86_SIB_BASE(sib)  + 8*rex_b;
20616ef7f15SPeter Zijlstra 	}
207baa41469SJosh Poimboeuf 
208442f04c3SJosh Poimboeuf 	switch (op1) {
209baa41469SJosh Poimboeuf 
210baa41469SJosh Poimboeuf 	case 0x1:
211baa41469SJosh Poimboeuf 	case 0x29:
21236d92e43SPeter Zijlstra 		if (rex_w && rm_is_reg(CFI_SP)) {
213baa41469SJosh Poimboeuf 
214baa41469SJosh Poimboeuf 			/* add/sub reg, %rsp */
2157d989fcaSPeter Zijlstra 			ADD_OP(op) {
216baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_ADD;
21716ef7f15SPeter Zijlstra 				op->src.reg = modrm_reg;
218e7e83dd3SLukas Bulwahn 				op->dest.type = OP_DEST_REG;
219baa41469SJosh Poimboeuf 				op->dest.reg = CFI_SP;
220baa41469SJosh Poimboeuf 			}
2217d989fcaSPeter Zijlstra 		}
222442f04c3SJosh Poimboeuf 		break;
223442f04c3SJosh Poimboeuf 
224baa41469SJosh Poimboeuf 	case 0x50 ... 0x57:
225baa41469SJosh Poimboeuf 
226baa41469SJosh Poimboeuf 		/* push reg */
2277d989fcaSPeter Zijlstra 		ADD_OP(op) {
228baa41469SJosh Poimboeuf 			op->src.type = OP_SRC_REG;
22916ef7f15SPeter Zijlstra 			op->src.reg = (op1 & 0x7) + 8*rex_b;
230baa41469SJosh Poimboeuf 			op->dest.type = OP_DEST_PUSH;
2317d989fcaSPeter Zijlstra 		}
232baa41469SJosh Poimboeuf 
233baa41469SJosh Poimboeuf 		break;
234baa41469SJosh Poimboeuf 
235baa41469SJosh Poimboeuf 	case 0x58 ... 0x5f:
236baa41469SJosh Poimboeuf 
237baa41469SJosh Poimboeuf 		/* pop reg */
2387d989fcaSPeter Zijlstra 		ADD_OP(op) {
239baa41469SJosh Poimboeuf 			op->src.type = OP_SRC_POP;
240baa41469SJosh Poimboeuf 			op->dest.type = OP_DEST_REG;
24116ef7f15SPeter Zijlstra 			op->dest.reg = (op1 & 0x7) + 8*rex_b;
2427d989fcaSPeter Zijlstra 		}
243baa41469SJosh Poimboeuf 
244baa41469SJosh Poimboeuf 		break;
245baa41469SJosh Poimboeuf 
246baa41469SJosh Poimboeuf 	case 0x68:
247baa41469SJosh Poimboeuf 	case 0x6a:
248baa41469SJosh Poimboeuf 		/* push immediate */
2497d989fcaSPeter Zijlstra 		ADD_OP(op) {
250baa41469SJosh Poimboeuf 			op->src.type = OP_SRC_CONST;
251baa41469SJosh Poimboeuf 			op->dest.type = OP_DEST_PUSH;
2527d989fcaSPeter Zijlstra 		}
253442f04c3SJosh Poimboeuf 		break;
254442f04c3SJosh Poimboeuf 
255442f04c3SJosh Poimboeuf 	case 0x70 ... 0x7f:
25620a55463SPeter Zijlstra 		insn->type = INSN_JUMP_CONDITIONAL;
257442f04c3SJosh Poimboeuf 		break;
258442f04c3SJosh Poimboeuf 
259961d83b9SPeter Zijlstra 	case 0x80 ... 0x83:
260961d83b9SPeter Zijlstra 		/*
261961d83b9SPeter Zijlstra 		 * 1000 00sw : mod OP r/m : immediate
262961d83b9SPeter Zijlstra 		 *
263961d83b9SPeter Zijlstra 		 * s - sign extend immediate
264961d83b9SPeter Zijlstra 		 * w - imm8 / imm32
265961d83b9SPeter Zijlstra 		 *
266961d83b9SPeter Zijlstra 		 * OP: 000 ADD    100 AND
267961d83b9SPeter Zijlstra 		 *     001 OR     101 SUB
268961d83b9SPeter Zijlstra 		 *     010 ADC    110 XOR
269961d83b9SPeter Zijlstra 		 *     011 SBB    111 CMP
270961d83b9SPeter Zijlstra 		 */
271961d83b9SPeter Zijlstra 
272961d83b9SPeter Zijlstra 		/* 64bit only */
273961d83b9SPeter Zijlstra 		if (!rex_w)
274baa41469SJosh Poimboeuf 			break;
275baa41469SJosh Poimboeuf 
276961d83b9SPeter Zijlstra 		/* %rsp target only */
27736d92e43SPeter Zijlstra 		if (!rm_is_reg(CFI_SP))
278961d83b9SPeter Zijlstra 			break;
279961d83b9SPeter Zijlstra 
28020a55463SPeter Zijlstra 		imm = ins.immediate.value;
281961d83b9SPeter Zijlstra 		if (op1 & 2) { /* sign extend */
282961d83b9SPeter Zijlstra 			if (op1 & 1) { /* imm32 */
283961d83b9SPeter Zijlstra 				imm <<= 32;
284961d83b9SPeter Zijlstra 				imm = (s64)imm >> 32;
285961d83b9SPeter Zijlstra 			} else { /* imm8 */
286961d83b9SPeter Zijlstra 				imm <<= 56;
287961d83b9SPeter Zijlstra 				imm = (s64)imm >> 56;
288961d83b9SPeter Zijlstra 			}
289961d83b9SPeter Zijlstra 		}
290961d83b9SPeter Zijlstra 
291961d83b9SPeter Zijlstra 		switch (modrm_reg & 7) {
292961d83b9SPeter Zijlstra 		case 5:
293961d83b9SPeter Zijlstra 			imm = -imm;
294961d83b9SPeter Zijlstra 			/* fallthrough */
295961d83b9SPeter Zijlstra 		case 0:
296961d83b9SPeter Zijlstra 			/* add/sub imm, %rsp */
297961d83b9SPeter Zijlstra 			ADD_OP(op) {
298961d83b9SPeter Zijlstra 				op->src.type = OP_SRC_ADD;
299961d83b9SPeter Zijlstra 				op->src.reg = CFI_SP;
300961d83b9SPeter Zijlstra 				op->src.offset = imm;
301961d83b9SPeter Zijlstra 				op->dest.type = OP_DEST_REG;
302961d83b9SPeter Zijlstra 				op->dest.reg = CFI_SP;
303961d83b9SPeter Zijlstra 			}
304961d83b9SPeter Zijlstra 			break;
305961d83b9SPeter Zijlstra 
306961d83b9SPeter Zijlstra 		case 4:
307baa41469SJosh Poimboeuf 			/* and imm, %rsp */
3087d989fcaSPeter Zijlstra 			ADD_OP(op) {
309baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_AND;
310baa41469SJosh Poimboeuf 				op->src.reg = CFI_SP;
31120a55463SPeter Zijlstra 				op->src.offset = ins.immediate.value;
312baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_REG;
313baa41469SJosh Poimboeuf 				op->dest.reg = CFI_SP;
3147d989fcaSPeter Zijlstra 			}
315baa41469SJosh Poimboeuf 			break;
316baa41469SJosh Poimboeuf 
317961d83b9SPeter Zijlstra 		default:
318961d83b9SPeter Zijlstra 			/* WARN ? */
319baa41469SJosh Poimboeuf 			break;
3207d989fcaSPeter Zijlstra 		}
321961d83b9SPeter Zijlstra 
322baa41469SJosh Poimboeuf 		break;
323baa41469SJosh Poimboeuf 
324442f04c3SJosh Poimboeuf 	case 0x89:
32578df6245SPeter Zijlstra 		if (!rex_w)
32678df6245SPeter Zijlstra 			break;
327baa41469SJosh Poimboeuf 
32878df6245SPeter Zijlstra 		if (modrm_reg == CFI_SP) {
329baa41469SJosh Poimboeuf 
33036d92e43SPeter Zijlstra 			if (mod_is_reg()) {
3310d0970eeSJosh Poimboeuf 				/* mov %rsp, reg */
3327d989fcaSPeter Zijlstra 				ADD_OP(op) {
333baa41469SJosh Poimboeuf 					op->src.type = OP_SRC_REG;
334baa41469SJosh Poimboeuf 					op->src.reg = CFI_SP;
335baa41469SJosh Poimboeuf 					op->dest.type = OP_DEST_REG;
33616ef7f15SPeter Zijlstra 					op->dest.reg = modrm_rm;
3377d989fcaSPeter Zijlstra 				}
338baa41469SJosh Poimboeuf 				break;
3392a512829SPeter Zijlstra 
3402a512829SPeter Zijlstra 			} else {
34178df6245SPeter Zijlstra 				/* skip RIP relative displacement */
34278df6245SPeter Zijlstra 				if (is_RIP())
3432a512829SPeter Zijlstra 					break;
3442a512829SPeter Zijlstra 
34578df6245SPeter Zijlstra 				/* skip nontrivial SIB */
34678df6245SPeter Zijlstra 				if (have_SIB()) {
34778df6245SPeter Zijlstra 					modrm_rm = sib_base;
34878df6245SPeter Zijlstra 					if (sib_index != CFI_SP)
3492a512829SPeter Zijlstra 						break;
35078df6245SPeter Zijlstra 				}
3512a512829SPeter Zijlstra 
3522a512829SPeter Zijlstra 				/* mov %rsp, disp(%reg) */
3532a512829SPeter Zijlstra 				ADD_OP(op) {
3542a512829SPeter Zijlstra 					op->src.type = OP_SRC_REG;
3552a512829SPeter Zijlstra 					op->src.reg = CFI_SP;
3562a512829SPeter Zijlstra 					op->dest.type = OP_DEST_REG_INDIRECT;
35716ef7f15SPeter Zijlstra 					op->dest.reg = modrm_rm;
35820a55463SPeter Zijlstra 					op->dest.offset = ins.displacement.value;
3592a512829SPeter Zijlstra 				}
3602a512829SPeter Zijlstra 				break;
3612a512829SPeter Zijlstra 			}
3622a512829SPeter Zijlstra 
3632a512829SPeter Zijlstra 			break;
364baa41469SJosh Poimboeuf 		}
365dd88a0a0SJosh Poimboeuf 
36636d92e43SPeter Zijlstra 		if (rm_is_reg(CFI_SP)) {
367dd88a0a0SJosh Poimboeuf 
368dd88a0a0SJosh Poimboeuf 			/* mov reg, %rsp */
3697d989fcaSPeter Zijlstra 			ADD_OP(op) {
370dd88a0a0SJosh Poimboeuf 				op->src.type = OP_SRC_REG;
37116ef7f15SPeter Zijlstra 				op->src.reg = modrm_reg;
372dd88a0a0SJosh Poimboeuf 				op->dest.type = OP_DEST_REG;
373dd88a0a0SJosh Poimboeuf 				op->dest.reg = CFI_SP;
3747d989fcaSPeter Zijlstra 			}
375dd88a0a0SJosh Poimboeuf 			break;
376dd88a0a0SJosh Poimboeuf 		}
377dd88a0a0SJosh Poimboeuf 
378baa41469SJosh Poimboeuf 		/* fallthrough */
379baa41469SJosh Poimboeuf 	case 0x88:
38078df6245SPeter Zijlstra 		if (!rex_w)
38178df6245SPeter Zijlstra 			break;
38278df6245SPeter Zijlstra 
38336d92e43SPeter Zijlstra 		if (rm_is_mem(CFI_BP)) {
384baa41469SJosh Poimboeuf 
385baa41469SJosh Poimboeuf 			/* mov reg, disp(%rbp) */
3867d989fcaSPeter Zijlstra 			ADD_OP(op) {
387baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_REG;
38816ef7f15SPeter Zijlstra 				op->src.reg = modrm_reg;
389baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_REG_INDIRECT;
390baa41469SJosh Poimboeuf 				op->dest.reg = CFI_BP;
39120a55463SPeter Zijlstra 				op->dest.offset = ins.displacement.value;
3927d989fcaSPeter Zijlstra 			}
3932a512829SPeter Zijlstra 			break;
3942a512829SPeter Zijlstra 		}
395baa41469SJosh Poimboeuf 
39636d92e43SPeter Zijlstra 		if (rm_is_mem(CFI_SP)) {
397baa41469SJosh Poimboeuf 
398baa41469SJosh Poimboeuf 			/* mov reg, disp(%rsp) */
3997d989fcaSPeter Zijlstra 			ADD_OP(op) {
400baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_REG;
40116ef7f15SPeter Zijlstra 				op->src.reg = modrm_reg;
402baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_REG_INDIRECT;
403baa41469SJosh Poimboeuf 				op->dest.reg = CFI_SP;
40420a55463SPeter Zijlstra 				op->dest.offset = ins.displacement.value;
405baa41469SJosh Poimboeuf 			}
4062a512829SPeter Zijlstra 			break;
4077d989fcaSPeter Zijlstra 		}
408baa41469SJosh Poimboeuf 
409baa41469SJosh Poimboeuf 		break;
410baa41469SJosh Poimboeuf 
411baa41469SJosh Poimboeuf 	case 0x8b:
41216ef7f15SPeter Zijlstra 		if (!rex_w)
41316ef7f15SPeter Zijlstra 			break;
41416ef7f15SPeter Zijlstra 
41536d92e43SPeter Zijlstra 		if (rm_is_mem(CFI_BP)) {
416baa41469SJosh Poimboeuf 
417baa41469SJosh Poimboeuf 			/* mov disp(%rbp), reg */
4187d989fcaSPeter Zijlstra 			ADD_OP(op) {
419baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_REG_INDIRECT;
420baa41469SJosh Poimboeuf 				op->src.reg = CFI_BP;
42120a55463SPeter Zijlstra 				op->src.offset = ins.displacement.value;
422baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_REG;
42316ef7f15SPeter Zijlstra 				op->dest.reg = modrm_reg;
42416ef7f15SPeter Zijlstra 			}
42516ef7f15SPeter Zijlstra 			break;
4267d989fcaSPeter Zijlstra 		}
427baa41469SJosh Poimboeuf 
42836d92e43SPeter Zijlstra 		if (rm_is_mem(CFI_SP)) {
429baa41469SJosh Poimboeuf 
430baa41469SJosh Poimboeuf 			/* mov disp(%rsp), reg */
4317d989fcaSPeter Zijlstra 			ADD_OP(op) {
432baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_REG_INDIRECT;
433baa41469SJosh Poimboeuf 				op->src.reg = CFI_SP;
43420a55463SPeter Zijlstra 				op->src.offset = ins.displacement.value;
435baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_REG;
43616ef7f15SPeter Zijlstra 				op->dest.reg = modrm_reg;
437baa41469SJosh Poimboeuf 			}
43816ef7f15SPeter Zijlstra 			break;
4397d989fcaSPeter Zijlstra 		}
440baa41469SJosh Poimboeuf 
441442f04c3SJosh Poimboeuf 		break;
442442f04c3SJosh Poimboeuf 
4432cc17fdaSJosh Poimboeuf 	case 0x8d:
44436d92e43SPeter Zijlstra 		if (mod_is_reg()) {
4452ee0c363SPeter Zijlstra 			WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset);
4462ee0c363SPeter Zijlstra 			break;
4472ee0c363SPeter Zijlstra 		}
448dd88a0a0SJosh Poimboeuf 
4492ee0c363SPeter Zijlstra 		/* skip non 64bit ops */
4502ee0c363SPeter Zijlstra 		if (!rex_w)
4512ee0c363SPeter Zijlstra 			break;
4522ee0c363SPeter Zijlstra 
45378df6245SPeter Zijlstra 		/* skip RIP relative displacement */
45478df6245SPeter Zijlstra 		if (is_RIP())
4552ee0c363SPeter Zijlstra 			break;
4562ee0c363SPeter Zijlstra 
45778df6245SPeter Zijlstra 		/* skip nontrivial SIB */
45878df6245SPeter Zijlstra 		if (have_SIB()) {
45978df6245SPeter Zijlstra 			modrm_rm = sib_base;
46078df6245SPeter Zijlstra 			if (sib_index != CFI_SP)
4612ee0c363SPeter Zijlstra 				break;
46278df6245SPeter Zijlstra 		}
4632ee0c363SPeter Zijlstra 
4642ee0c363SPeter Zijlstra 		/* lea disp(%src), %dst */
4657d989fcaSPeter Zijlstra 		ADD_OP(op) {
46620a55463SPeter Zijlstra 			op->src.offset = ins.displacement.value;
4672ee0c363SPeter Zijlstra 			if (!op->src.offset) {
4682ee0c363SPeter Zijlstra 				/* lea (%src), %dst */
469607a4029SJosh Poimboeuf 				op->src.type = OP_SRC_REG;
470607a4029SJosh Poimboeuf 			} else {
4712ee0c363SPeter Zijlstra 				/* lea disp(%src), %dst */
472dd88a0a0SJosh Poimboeuf 				op->src.type = OP_SRC_ADD;
473607a4029SJosh Poimboeuf 			}
47416ef7f15SPeter Zijlstra 			op->src.reg = modrm_rm;
475dd88a0a0SJosh Poimboeuf 			op->dest.type = OP_DEST_REG;
47616ef7f15SPeter Zijlstra 			op->dest.reg = modrm_reg;
4777d989fcaSPeter Zijlstra 		}
478baa41469SJosh Poimboeuf 		break;
479baa41469SJosh Poimboeuf 
480baa41469SJosh Poimboeuf 	case 0x8f:
481baa41469SJosh Poimboeuf 		/* pop to mem */
4827d989fcaSPeter Zijlstra 		ADD_OP(op) {
483baa41469SJosh Poimboeuf 			op->src.type = OP_SRC_POP;
484baa41469SJosh Poimboeuf 			op->dest.type = OP_DEST_MEM;
4857d989fcaSPeter Zijlstra 		}
4862cc17fdaSJosh Poimboeuf 		break;
4872cc17fdaSJosh Poimboeuf 
488442f04c3SJosh Poimboeuf 	case 0x90:
48920a55463SPeter Zijlstra 		insn->type = INSN_NOP;
490442f04c3SJosh Poimboeuf 		break;
491442f04c3SJosh Poimboeuf 
492baa41469SJosh Poimboeuf 	case 0x9c:
493baa41469SJosh Poimboeuf 		/* pushf */
4947d989fcaSPeter Zijlstra 		ADD_OP(op) {
495baa41469SJosh Poimboeuf 			op->src.type = OP_SRC_CONST;
496ea24213dSPeter Zijlstra 			op->dest.type = OP_DEST_PUSHF;
4977d989fcaSPeter Zijlstra 		}
498baa41469SJosh Poimboeuf 		break;
499baa41469SJosh Poimboeuf 
500baa41469SJosh Poimboeuf 	case 0x9d:
501baa41469SJosh Poimboeuf 		/* popf */
5027d989fcaSPeter Zijlstra 		ADD_OP(op) {
503ea24213dSPeter Zijlstra 			op->src.type = OP_SRC_POPF;
504baa41469SJosh Poimboeuf 			op->dest.type = OP_DEST_MEM;
5057d989fcaSPeter Zijlstra 		}
506baa41469SJosh Poimboeuf 		break;
507baa41469SJosh Poimboeuf 
508442f04c3SJosh Poimboeuf 	case 0x0f:
509baa41469SJosh Poimboeuf 
510ea24213dSPeter Zijlstra 		if (op2 == 0x01) {
511ea24213dSPeter Zijlstra 
512ea24213dSPeter Zijlstra 			if (modrm == 0xca)
51320a55463SPeter Zijlstra 				insn->type = INSN_CLAC;
514ea24213dSPeter Zijlstra 			else if (modrm == 0xcb)
51520a55463SPeter Zijlstra 				insn->type = INSN_STAC;
516ea24213dSPeter Zijlstra 
517ea24213dSPeter Zijlstra 		} else if (op2 >= 0x80 && op2 <= 0x8f) {
518649ea4d5SJosh Poimboeuf 
51920a55463SPeter Zijlstra 			insn->type = INSN_JUMP_CONDITIONAL;
520649ea4d5SJosh Poimboeuf 
521649ea4d5SJosh Poimboeuf 		} else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
522649ea4d5SJosh Poimboeuf 			   op2 == 0x35) {
523baa41469SJosh Poimboeuf 
524442f04c3SJosh Poimboeuf 			/* sysenter, sysret */
52520a55463SPeter Zijlstra 			insn->type = INSN_CONTEXT_SWITCH;
526baa41469SJosh Poimboeuf 
527649ea4d5SJosh Poimboeuf 		} else if (op2 == 0x0b || op2 == 0xb9) {
528649ea4d5SJosh Poimboeuf 
529649ea4d5SJosh Poimboeuf 			/* ud2 */
53020a55463SPeter Zijlstra 			insn->type = INSN_BUG;
531649ea4d5SJosh Poimboeuf 
532649ea4d5SJosh Poimboeuf 		} else if (op2 == 0x0d || op2 == 0x1f) {
533baa41469SJosh Poimboeuf 
534442f04c3SJosh Poimboeuf 			/* nopl/nopw */
53520a55463SPeter Zijlstra 			insn->type = INSN_NOP;
536baa41469SJosh Poimboeuf 
5377d209d13SPeter Zijlstra 		} else if (op2 == 0x1e) {
5387d209d13SPeter Zijlstra 
5397d209d13SPeter Zijlstra 			if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb))
54020a55463SPeter Zijlstra 				insn->type = INSN_ENDBR;
5417d209d13SPeter Zijlstra 
5427d209d13SPeter Zijlstra 
543227a0655SFenghua Yu 		} else if (op2 == 0x38 && op3 == 0xf8) {
54420a55463SPeter Zijlstra 			if (ins.prefixes.nbytes == 1 &&
54520a55463SPeter Zijlstra 			    ins.prefixes.bytes[0] == 0xf2) {
546227a0655SFenghua Yu 				/* ENQCMD cannot be used in the kernel. */
547227a0655SFenghua Yu 				WARN("ENQCMD instruction at %s:%lx", sec->name,
548227a0655SFenghua Yu 				     offset);
549227a0655SFenghua Yu 			}
550227a0655SFenghua Yu 
551649ea4d5SJosh Poimboeuf 		} else if (op2 == 0xa0 || op2 == 0xa8) {
552baa41469SJosh Poimboeuf 
553baa41469SJosh Poimboeuf 			/* push fs/gs */
5547d989fcaSPeter Zijlstra 			ADD_OP(op) {
555baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_CONST;
556baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_PUSH;
5577d989fcaSPeter Zijlstra 			}
558baa41469SJosh Poimboeuf 
559baa41469SJosh Poimboeuf 		} else if (op2 == 0xa1 || op2 == 0xa9) {
560baa41469SJosh Poimboeuf 
561baa41469SJosh Poimboeuf 			/* pop fs/gs */
5627d989fcaSPeter Zijlstra 			ADD_OP(op) {
563baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_POP;
564baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_MEM;
565baa41469SJosh Poimboeuf 			}
5667d989fcaSPeter Zijlstra 		}
567442f04c3SJosh Poimboeuf 
568442f04c3SJosh Poimboeuf 		break;
569442f04c3SJosh Poimboeuf 
570baa41469SJosh Poimboeuf 	case 0xc9:
571baa41469SJosh Poimboeuf 		/*
572baa41469SJosh Poimboeuf 		 * leave
573baa41469SJosh Poimboeuf 		 *
574baa41469SJosh Poimboeuf 		 * equivalent to:
575baa41469SJosh Poimboeuf 		 * mov bp, sp
576baa41469SJosh Poimboeuf 		 * pop bp
577baa41469SJosh Poimboeuf 		 */
578ffc7e74fSPeter Zijlstra 		ADD_OP(op) {
579ffc7e74fSPeter Zijlstra 			op->src.type = OP_SRC_REG;
580ffc7e74fSPeter Zijlstra 			op->src.reg = CFI_BP;
581ffc7e74fSPeter Zijlstra 			op->dest.type = OP_DEST_REG;
582ffc7e74fSPeter Zijlstra 			op->dest.reg = CFI_SP;
583ffc7e74fSPeter Zijlstra 		}
584ffc7e74fSPeter Zijlstra 		ADD_OP(op) {
585ffc7e74fSPeter Zijlstra 			op->src.type = OP_SRC_POP;
586ffc7e74fSPeter Zijlstra 			op->dest.type = OP_DEST_REG;
587ffc7e74fSPeter Zijlstra 			op->dest.reg = CFI_BP;
588ffc7e74fSPeter Zijlstra 		}
589442f04c3SJosh Poimboeuf 		break;
590442f04c3SJosh Poimboeuf 
5911cc1e4c8SPeter Zijlstra 	case 0xcc:
5921cc1e4c8SPeter Zijlstra 		/* int3 */
59320a55463SPeter Zijlstra 		insn->type = INSN_TRAP;
5941cc1e4c8SPeter Zijlstra 		break;
5951cc1e4c8SPeter Zijlstra 
596baa41469SJosh Poimboeuf 	case 0xe3:
597baa41469SJosh Poimboeuf 		/* jecxz/jrcxz */
59820a55463SPeter Zijlstra 		insn->type = INSN_JUMP_CONDITIONAL;
599442f04c3SJosh Poimboeuf 		break;
600442f04c3SJosh Poimboeuf 
601442f04c3SJosh Poimboeuf 	case 0xe9:
602442f04c3SJosh Poimboeuf 	case 0xeb:
60320a55463SPeter Zijlstra 		insn->type = INSN_JUMP_UNCONDITIONAL;
604442f04c3SJosh Poimboeuf 		break;
605442f04c3SJosh Poimboeuf 
606442f04c3SJosh Poimboeuf 	case 0xc2:
607442f04c3SJosh Poimboeuf 	case 0xc3:
60820a55463SPeter Zijlstra 		insn->type = INSN_RETURN;
609442f04c3SJosh Poimboeuf 		break;
610442f04c3SJosh Poimboeuf 
611db2b0c5dSPeter Zijlstra 	case 0xc7: /* mov imm, r/m */
6122daf7fabSJosh Poimboeuf 		if (!opts.noinstr)
613db2b0c5dSPeter Zijlstra 			break;
614db2b0c5dSPeter Zijlstra 
61520a55463SPeter Zijlstra 		if (ins.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) {
616db2b0c5dSPeter Zijlstra 			struct reloc *immr, *disp;
617db2b0c5dSPeter Zijlstra 			struct symbol *func;
618db2b0c5dSPeter Zijlstra 			int idx;
619db2b0c5dSPeter Zijlstra 
620db2b0c5dSPeter Zijlstra 			immr = find_reloc_by_dest(elf, (void *)sec, offset+3);
621db2b0c5dSPeter Zijlstra 			disp = find_reloc_by_dest(elf, (void *)sec, offset+7);
622db2b0c5dSPeter Zijlstra 
623db2b0c5dSPeter Zijlstra 			if (!immr || strcmp(immr->sym->name, "pv_ops"))
624db2b0c5dSPeter Zijlstra 				break;
625db2b0c5dSPeter Zijlstra 
6260696b6e3SJosh Poimboeuf 			idx = (reloc_addend(immr) + 8) / sizeof(void *);
627db2b0c5dSPeter Zijlstra 
628db2b0c5dSPeter Zijlstra 			func = disp->sym;
629db2b0c5dSPeter Zijlstra 			if (disp->sym->type == STT_SECTION)
6300696b6e3SJosh Poimboeuf 				func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
631db2b0c5dSPeter Zijlstra 			if (!func) {
632db2b0c5dSPeter Zijlstra 				WARN("no func for pv_ops[]");
633db2b0c5dSPeter Zijlstra 				return -1;
634db2b0c5dSPeter Zijlstra 			}
635db2b0c5dSPeter Zijlstra 
636db2b0c5dSPeter Zijlstra 			objtool_pv_add(file, idx, func);
637db2b0c5dSPeter Zijlstra 		}
638db2b0c5dSPeter Zijlstra 
639db2b0c5dSPeter Zijlstra 		break;
640db2b0c5dSPeter Zijlstra 
641b7460462SPeter Zijlstra 	case 0xcf: /* iret */
642b490f453SMiroslav Benes 		/*
643b490f453SMiroslav Benes 		 * Handle sync_core(), which has an IRET to self.
644b490f453SMiroslav Benes 		 * All other IRET are in STT_NONE entry code.
645b490f453SMiroslav Benes 		 */
646b490f453SMiroslav Benes 		sym = find_symbol_containing(sec, offset);
647b490f453SMiroslav Benes 		if (sym && sym->type == STT_FUNC) {
6487d989fcaSPeter Zijlstra 			ADD_OP(op) {
649b7460462SPeter Zijlstra 				/* add $40, %rsp */
650b7460462SPeter Zijlstra 				op->src.type = OP_SRC_ADD;
651b7460462SPeter Zijlstra 				op->src.reg = CFI_SP;
652b7460462SPeter Zijlstra 				op->src.offset = 5*8;
653b7460462SPeter Zijlstra 				op->dest.type = OP_DEST_REG;
654b7460462SPeter Zijlstra 				op->dest.reg = CFI_SP;
6557d989fcaSPeter Zijlstra 			}
656b7460462SPeter Zijlstra 			break;
657b490f453SMiroslav Benes 		}
658b490f453SMiroslav Benes 
659b490f453SMiroslav Benes 		/* fallthrough */
660b7460462SPeter Zijlstra 
661442f04c3SJosh Poimboeuf 	case 0xca: /* retf */
662442f04c3SJosh Poimboeuf 	case 0xcb: /* retf */
66320a55463SPeter Zijlstra 		insn->type = INSN_CONTEXT_SWITCH;
664442f04c3SJosh Poimboeuf 		break;
665442f04c3SJosh Poimboeuf 
6667a7621dfSPeter Zijlstra 	case 0xe0: /* loopne */
6677a7621dfSPeter Zijlstra 	case 0xe1: /* loope */
6687a7621dfSPeter Zijlstra 	case 0xe2: /* loop */
66920a55463SPeter Zijlstra 		insn->type = INSN_JUMP_CONDITIONAL;
6707a7621dfSPeter Zijlstra 		break;
6717a7621dfSPeter Zijlstra 
672442f04c3SJosh Poimboeuf 	case 0xe8:
67320a55463SPeter Zijlstra 		insn->type = INSN_CALL;
6748aa8eb2aSAlexandre Chartre 		/*
6758aa8eb2aSAlexandre Chartre 		 * For the impact on the stack, a CALL behaves like
6768aa8eb2aSAlexandre Chartre 		 * a PUSH of an immediate value (the return address).
6778aa8eb2aSAlexandre Chartre 		 */
6788aa8eb2aSAlexandre Chartre 		ADD_OP(op) {
6798aa8eb2aSAlexandre Chartre 			op->src.type = OP_SRC_CONST;
6808aa8eb2aSAlexandre Chartre 			op->dest.type = OP_DEST_PUSH;
6818aa8eb2aSAlexandre Chartre 		}
682442f04c3SJosh Poimboeuf 		break;
683442f04c3SJosh Poimboeuf 
6842f0f9e9aSPeter Zijlstra 	case 0xfc:
68520a55463SPeter Zijlstra 		insn->type = INSN_CLD;
6862f0f9e9aSPeter Zijlstra 		break;
6872f0f9e9aSPeter Zijlstra 
6882f0f9e9aSPeter Zijlstra 	case 0xfd:
68920a55463SPeter Zijlstra 		insn->type = INSN_STD;
6902f0f9e9aSPeter Zijlstra 		break;
6912f0f9e9aSPeter Zijlstra 
692442f04c3SJosh Poimboeuf 	case 0xff:
6937d209d13SPeter Zijlstra 		if (modrm_reg == 2 || modrm_reg == 3) {
694baa41469SJosh Poimboeuf 
69520a55463SPeter Zijlstra 			insn->type = INSN_CALL_DYNAMIC;
69620a55463SPeter Zijlstra 			if (has_notrack_prefix(&ins))
6977d209d13SPeter Zijlstra 				WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
698baa41469SJosh Poimboeuf 
6997d209d13SPeter Zijlstra 		} else if (modrm_reg == 4) {
700baa41469SJosh Poimboeuf 
70120a55463SPeter Zijlstra 			insn->type = INSN_JUMP_DYNAMIC;
70220a55463SPeter Zijlstra 			if (has_notrack_prefix(&ins))
7037d209d13SPeter Zijlstra 				WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
704baa41469SJosh Poimboeuf 
7057d209d13SPeter Zijlstra 		} else if (modrm_reg == 5) {
706baa41469SJosh Poimboeuf 
707baa41469SJosh Poimboeuf 			/* jmpf */
70820a55463SPeter Zijlstra 			insn->type = INSN_CONTEXT_SWITCH;
709442f04c3SJosh Poimboeuf 
7107d209d13SPeter Zijlstra 		} else if (modrm_reg == 6) {
711baa41469SJosh Poimboeuf 
712baa41469SJosh Poimboeuf 			/* push from mem */
7137d989fcaSPeter Zijlstra 			ADD_OP(op) {
714baa41469SJosh Poimboeuf 				op->src.type = OP_SRC_CONST;
715baa41469SJosh Poimboeuf 				op->dest.type = OP_DEST_PUSH;
716baa41469SJosh Poimboeuf 			}
7177d989fcaSPeter Zijlstra 		}
718baa41469SJosh Poimboeuf 
719442f04c3SJosh Poimboeuf 		break;
720442f04c3SJosh Poimboeuf 
721442f04c3SJosh Poimboeuf 	default:
722442f04c3SJosh Poimboeuf 		break;
723442f04c3SJosh Poimboeuf 	}
724442f04c3SJosh Poimboeuf 
72520a55463SPeter Zijlstra 	insn->immediate = ins.immediate.nbytes ? ins.immediate.value : 0;
726442f04c3SJosh Poimboeuf 
727442f04c3SJosh Poimboeuf 	return 0;
728442f04c3SJosh Poimboeuf }
729baa41469SJosh Poimboeuf 
arch_initial_func_cfi_state(struct cfi_init_state * state)730a3608f59SPeter Zijlstra void arch_initial_func_cfi_state(struct cfi_init_state *state)
731baa41469SJosh Poimboeuf {
732baa41469SJosh Poimboeuf 	int i;
733baa41469SJosh Poimboeuf 
734baa41469SJosh Poimboeuf 	for (i = 0; i < CFI_NUM_REGS; i++) {
735baa41469SJosh Poimboeuf 		state->regs[i].base = CFI_UNDEFINED;
736baa41469SJosh Poimboeuf 		state->regs[i].offset = 0;
737baa41469SJosh Poimboeuf 	}
738baa41469SJosh Poimboeuf 
739baa41469SJosh Poimboeuf 	/* initial CFA (call frame address) */
740baa41469SJosh Poimboeuf 	state->cfa.base = CFI_SP;
741baa41469SJosh Poimboeuf 	state->cfa.offset = 8;
742baa41469SJosh Poimboeuf 
743baa41469SJosh Poimboeuf 	/* initial RA (return address) */
744b735bd3eSJosh Poimboeuf 	state->regs[CFI_RA].base = CFI_CFA;
745b735bd3eSJosh Poimboeuf 	state->regs[CFI_RA].offset = -8;
746baa41469SJosh Poimboeuf }
7470f1441b4SPeter Zijlstra 
arch_nop_insn(int len)7480f1441b4SPeter Zijlstra const char *arch_nop_insn(int len)
7490f1441b4SPeter Zijlstra {
7500f1441b4SPeter Zijlstra 	static const char nops[5][5] = {
751301cddc2SPeter Zijlstra 		{ BYTES_NOP1 },
752301cddc2SPeter Zijlstra 		{ BYTES_NOP2 },
753301cddc2SPeter Zijlstra 		{ BYTES_NOP3 },
754301cddc2SPeter Zijlstra 		{ BYTES_NOP4 },
755301cddc2SPeter Zijlstra 		{ BYTES_NOP5 },
7560f1441b4SPeter Zijlstra 	};
7570f1441b4SPeter Zijlstra 
7580f1441b4SPeter Zijlstra 	if (len < 1 || len > 5) {
7590f1441b4SPeter Zijlstra 		WARN("invalid NOP size: %d\n", len);
7600f1441b4SPeter Zijlstra 		return NULL;
7610f1441b4SPeter Zijlstra 	}
7620f1441b4SPeter Zijlstra 
7630f1441b4SPeter Zijlstra 	return nops[len-1];
7640f1441b4SPeter Zijlstra }
765edea9e6bSJulien Thierry 
766f56dae88SPeter Zijlstra #define BYTE_RET	0xC3
767f56dae88SPeter Zijlstra 
arch_ret_insn(int len)768f56dae88SPeter Zijlstra const char *arch_ret_insn(int len)
769f56dae88SPeter Zijlstra {
770f56dae88SPeter Zijlstra 	static const char ret[5][5] = {
771f56dae88SPeter Zijlstra 		{ BYTE_RET },
7721cc1e4c8SPeter Zijlstra 		{ BYTE_RET, 0xcc },
7731cc1e4c8SPeter Zijlstra 		{ BYTE_RET, 0xcc, BYTES_NOP1 },
7741cc1e4c8SPeter Zijlstra 		{ BYTE_RET, 0xcc, BYTES_NOP2 },
7751cc1e4c8SPeter Zijlstra 		{ BYTE_RET, 0xcc, BYTES_NOP3 },
776f56dae88SPeter Zijlstra 	};
777f56dae88SPeter Zijlstra 
778f56dae88SPeter Zijlstra 	if (len < 1 || len > 5) {
779f56dae88SPeter Zijlstra 		WARN("invalid RET size: %d\n", len);
780f56dae88SPeter Zijlstra 		return NULL;
781f56dae88SPeter Zijlstra 	}
782f56dae88SPeter Zijlstra 
783f56dae88SPeter Zijlstra 	return ret[len-1];
784f56dae88SPeter Zijlstra }
785f56dae88SPeter Zijlstra 
arch_decode_hint_reg(u8 sp_reg,int * base)7868b946cc3SPeter Zijlstra int arch_decode_hint_reg(u8 sp_reg, int *base)
787edea9e6bSJulien Thierry {
788edea9e6bSJulien Thierry 	switch (sp_reg) {
789edea9e6bSJulien Thierry 	case ORC_REG_UNDEFINED:
7908b946cc3SPeter Zijlstra 		*base = CFI_UNDEFINED;
791edea9e6bSJulien Thierry 		break;
792edea9e6bSJulien Thierry 	case ORC_REG_SP:
7938b946cc3SPeter Zijlstra 		*base = CFI_SP;
794edea9e6bSJulien Thierry 		break;
795edea9e6bSJulien Thierry 	case ORC_REG_BP:
7968b946cc3SPeter Zijlstra 		*base = CFI_BP;
797edea9e6bSJulien Thierry 		break;
798edea9e6bSJulien Thierry 	case ORC_REG_SP_INDIRECT:
7998b946cc3SPeter Zijlstra 		*base = CFI_SP_INDIRECT;
800edea9e6bSJulien Thierry 		break;
801edea9e6bSJulien Thierry 	case ORC_REG_R10:
8028b946cc3SPeter Zijlstra 		*base = CFI_R10;
803edea9e6bSJulien Thierry 		break;
804edea9e6bSJulien Thierry 	case ORC_REG_R13:
8058b946cc3SPeter Zijlstra 		*base = CFI_R13;
806edea9e6bSJulien Thierry 		break;
807edea9e6bSJulien Thierry 	case ORC_REG_DI:
8088b946cc3SPeter Zijlstra 		*base = CFI_DI;
809edea9e6bSJulien Thierry 		break;
810edea9e6bSJulien Thierry 	case ORC_REG_DX:
8118b946cc3SPeter Zijlstra 		*base = CFI_DX;
812edea9e6bSJulien Thierry 		break;
813edea9e6bSJulien Thierry 	default:
814edea9e6bSJulien Thierry 		return -1;
815edea9e6bSJulien Thierry 	}
816edea9e6bSJulien Thierry 
817edea9e6bSJulien Thierry 	return 0;
818edea9e6bSJulien Thierry }
819530b4dddSPeter Zijlstra 
arch_is_retpoline(struct symbol * sym)820530b4dddSPeter Zijlstra bool arch_is_retpoline(struct symbol *sym)
821530b4dddSPeter Zijlstra {
822530b4dddSPeter Zijlstra 	return !strncmp(sym->name, "__x86_indirect_", 15);
823530b4dddSPeter Zijlstra }
824d9e9d230SPeter Zijlstra 
arch_is_rethunk(struct symbol * sym)825d9e9d230SPeter Zijlstra bool arch_is_rethunk(struct symbol *sym)
826d9e9d230SPeter Zijlstra {
8274ae68b26SPeter Zijlstra 	return !strcmp(sym->name, "__x86_return_thunk");
8284ae68b26SPeter Zijlstra }
8294ae68b26SPeter Zijlstra 
arch_is_embedded_insn(struct symbol * sym)8304ae68b26SPeter Zijlstra bool arch_is_embedded_insn(struct symbol *sym)
8314ae68b26SPeter Zijlstra {
832*d025b7baSPeter Zijlstra 	return !strcmp(sym->name, "retbleed_return_thunk") ||
8334ae68b26SPeter Zijlstra 	       !strcmp(sym->name, "srso_safe_ret");
834d9e9d230SPeter Zijlstra }
835