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