162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <stdio.h> 762306a36Sopenharmony_ci#include <stdlib.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define unlikely(cond) (cond) 1062306a36Sopenharmony_ci#include <asm/insn.h> 1162306a36Sopenharmony_ci#include "../../../arch/x86/lib/inat.c" 1262306a36Sopenharmony_ci#include "../../../arch/x86/lib/insn.c" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define CONFIG_64BIT 1 1562306a36Sopenharmony_ci#include <asm/nops.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/orc_types.h> 1862306a36Sopenharmony_ci#include <objtool/check.h> 1962306a36Sopenharmony_ci#include <objtool/elf.h> 2062306a36Sopenharmony_ci#include <objtool/arch.h> 2162306a36Sopenharmony_ci#include <objtool/warn.h> 2262306a36Sopenharmony_ci#include <objtool/endianness.h> 2362306a36Sopenharmony_ci#include <objtool/builtin.h> 2462306a36Sopenharmony_ci#include <arch/elf.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciint arch_ftrace_match(char *name) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci return !strcmp(name, "__fentry__"); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int is_x86_64(const struct elf *elf) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci switch (elf->ehdr.e_machine) { 3462306a36Sopenharmony_ci case EM_X86_64: 3562306a36Sopenharmony_ci return 1; 3662306a36Sopenharmony_ci case EM_386: 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci default: 3962306a36Sopenharmony_ci WARN("unexpected ELF machine type %d", elf->ehdr.e_machine); 4062306a36Sopenharmony_ci return -1; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cibool arch_callee_saved_reg(unsigned char reg) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci switch (reg) { 4762306a36Sopenharmony_ci case CFI_BP: 4862306a36Sopenharmony_ci case CFI_BX: 4962306a36Sopenharmony_ci case CFI_R12: 5062306a36Sopenharmony_ci case CFI_R13: 5162306a36Sopenharmony_ci case CFI_R14: 5262306a36Sopenharmony_ci case CFI_R15: 5362306a36Sopenharmony_ci return true; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci case CFI_AX: 5662306a36Sopenharmony_ci case CFI_CX: 5762306a36Sopenharmony_ci case CFI_DX: 5862306a36Sopenharmony_ci case CFI_SI: 5962306a36Sopenharmony_ci case CFI_DI: 6062306a36Sopenharmony_ci case CFI_SP: 6162306a36Sopenharmony_ci case CFI_R8: 6262306a36Sopenharmony_ci case CFI_R9: 6362306a36Sopenharmony_ci case CFI_R10: 6462306a36Sopenharmony_ci case CFI_R11: 6562306a36Sopenharmony_ci case CFI_RA: 6662306a36Sopenharmony_ci default: 6762306a36Sopenharmony_ci return false; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciunsigned long arch_dest_reloc_offset(int addend) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return addend + 4; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ciunsigned long arch_jump_destination(struct instruction *insn) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci return insn->offset + insn->len + insn->immediate; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cibool arch_pc_relative_reloc(struct reloc *reloc) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * All relocation types where P (the address of the target) 8562306a36Sopenharmony_ci * is included in the computation. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci switch (reloc_type(reloc)) { 8862306a36Sopenharmony_ci case R_X86_64_PC8: 8962306a36Sopenharmony_ci case R_X86_64_PC16: 9062306a36Sopenharmony_ci case R_X86_64_PC32: 9162306a36Sopenharmony_ci case R_X86_64_PC64: 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci case R_X86_64_PLT32: 9462306a36Sopenharmony_ci case R_X86_64_GOTPC32: 9562306a36Sopenharmony_ci case R_X86_64_GOTPCREL: 9662306a36Sopenharmony_ci return true; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci default: 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return false; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define ADD_OP(op) \ 10662306a36Sopenharmony_ci if (!(op = calloc(1, sizeof(*op)))) \ 10762306a36Sopenharmony_ci return -1; \ 10862306a36Sopenharmony_ci else for (*ops_list = op, ops_list = &op->next; op; op = NULL) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* 11162306a36Sopenharmony_ci * Helpers to decode ModRM/SIB: 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * r/m| AX CX DX BX | SP | BP | SI DI | 11462306a36Sopenharmony_ci * | R8 R9 R10 R11 | R12 | R13 | R14 R15 | 11562306a36Sopenharmony_ci * Mod+----------------+-----+-----+---------+ 11662306a36Sopenharmony_ci * 00 | [r/m] |[SIB]|[IP+]| [r/m] | 11762306a36Sopenharmony_ci * 01 | [r/m + d8] |[S+d]| [r/m + d8] | 11862306a36Sopenharmony_ci * 10 | [r/m + d32] |[S+D]| [r/m + d32] | 11962306a36Sopenharmony_ci * 11 | r/ m | 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define mod_is_mem() (modrm_mod != 3) 12362306a36Sopenharmony_ci#define mod_is_reg() (modrm_mod == 3) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define is_RIP() ((modrm_rm & 7) == CFI_BP && modrm_mod == 0) 12662306a36Sopenharmony_ci#define have_SIB() ((modrm_rm & 7) == CFI_SP && mod_is_mem()) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#define rm_is(reg) (have_SIB() ? \ 12962306a36Sopenharmony_ci sib_base == (reg) && sib_index == CFI_SP : \ 13062306a36Sopenharmony_ci modrm_rm == (reg)) 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define rm_is_mem(reg) (mod_is_mem() && !is_RIP() && rm_is(reg)) 13362306a36Sopenharmony_ci#define rm_is_reg(reg) (mod_is_reg() && modrm_rm == (reg)) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic bool has_notrack_prefix(struct insn *insn) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci int i; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci for (i = 0; i < insn->prefixes.nbytes; i++) { 14062306a36Sopenharmony_ci if (insn->prefixes.bytes[i] == 0x3e) 14162306a36Sopenharmony_ci return true; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return false; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciint arch_decode_instruction(struct objtool_file *file, const struct section *sec, 14862306a36Sopenharmony_ci unsigned long offset, unsigned int maxlen, 14962306a36Sopenharmony_ci struct instruction *insn) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct stack_op **ops_list = &insn->stack_ops; 15262306a36Sopenharmony_ci const struct elf *elf = file->elf; 15362306a36Sopenharmony_ci struct insn ins; 15462306a36Sopenharmony_ci int x86_64, ret; 15562306a36Sopenharmony_ci unsigned char op1, op2, op3, prefix, 15662306a36Sopenharmony_ci rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0, 15762306a36Sopenharmony_ci modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0, 15862306a36Sopenharmony_ci sib = 0, /* sib_scale = 0, */ sib_index = 0, sib_base = 0; 15962306a36Sopenharmony_ci struct stack_op *op = NULL; 16062306a36Sopenharmony_ci struct symbol *sym; 16162306a36Sopenharmony_ci u64 imm; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci x86_64 = is_x86_64(elf); 16462306a36Sopenharmony_ci if (x86_64 == -1) 16562306a36Sopenharmony_ci return -1; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ret = insn_decode(&ins, sec->data->d_buf + offset, maxlen, 16862306a36Sopenharmony_ci x86_64 ? INSN_MODE_64 : INSN_MODE_32); 16962306a36Sopenharmony_ci if (ret < 0) { 17062306a36Sopenharmony_ci WARN("can't decode instruction at %s:0x%lx", sec->name, offset); 17162306a36Sopenharmony_ci return -1; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci insn->len = ins.length; 17562306a36Sopenharmony_ci insn->type = INSN_OTHER; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (ins.vex_prefix.nbytes) 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci prefix = ins.prefixes.bytes[0]; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci op1 = ins.opcode.bytes[0]; 18362306a36Sopenharmony_ci op2 = ins.opcode.bytes[1]; 18462306a36Sopenharmony_ci op3 = ins.opcode.bytes[2]; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (ins.rex_prefix.nbytes) { 18762306a36Sopenharmony_ci rex = ins.rex_prefix.bytes[0]; 18862306a36Sopenharmony_ci rex_w = X86_REX_W(rex) >> 3; 18962306a36Sopenharmony_ci rex_r = X86_REX_R(rex) >> 2; 19062306a36Sopenharmony_ci rex_x = X86_REX_X(rex) >> 1; 19162306a36Sopenharmony_ci rex_b = X86_REX_B(rex); 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (ins.modrm.nbytes) { 19562306a36Sopenharmony_ci modrm = ins.modrm.bytes[0]; 19662306a36Sopenharmony_ci modrm_mod = X86_MODRM_MOD(modrm); 19762306a36Sopenharmony_ci modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r; 19862306a36Sopenharmony_ci modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (ins.sib.nbytes) { 20262306a36Sopenharmony_ci sib = ins.sib.bytes[0]; 20362306a36Sopenharmony_ci /* sib_scale = X86_SIB_SCALE(sib); */ 20462306a36Sopenharmony_ci sib_index = X86_SIB_INDEX(sib) + 8*rex_x; 20562306a36Sopenharmony_ci sib_base = X86_SIB_BASE(sib) + 8*rex_b; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci switch (op1) { 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci case 0x1: 21162306a36Sopenharmony_ci case 0x29: 21262306a36Sopenharmony_ci if (rex_w && rm_is_reg(CFI_SP)) { 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* add/sub reg, %rsp */ 21562306a36Sopenharmony_ci ADD_OP(op) { 21662306a36Sopenharmony_ci op->src.type = OP_SRC_ADD; 21762306a36Sopenharmony_ci op->src.reg = modrm_reg; 21862306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 21962306a36Sopenharmony_ci op->dest.reg = CFI_SP; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci case 0x50 ... 0x57: 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* push reg */ 22762306a36Sopenharmony_ci ADD_OP(op) { 22862306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 22962306a36Sopenharmony_ci op->src.reg = (op1 & 0x7) + 8*rex_b; 23062306a36Sopenharmony_ci op->dest.type = OP_DEST_PUSH; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci case 0x58 ... 0x5f: 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* pop reg */ 23862306a36Sopenharmony_ci ADD_OP(op) { 23962306a36Sopenharmony_ci op->src.type = OP_SRC_POP; 24062306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 24162306a36Sopenharmony_ci op->dest.reg = (op1 & 0x7) + 8*rex_b; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci case 0x68: 24762306a36Sopenharmony_ci case 0x6a: 24862306a36Sopenharmony_ci /* push immediate */ 24962306a36Sopenharmony_ci ADD_OP(op) { 25062306a36Sopenharmony_ci op->src.type = OP_SRC_CONST; 25162306a36Sopenharmony_ci op->dest.type = OP_DEST_PUSH; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci case 0x70 ... 0x7f: 25662306a36Sopenharmony_ci insn->type = INSN_JUMP_CONDITIONAL; 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci case 0x80 ... 0x83: 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * 1000 00sw : mod OP r/m : immediate 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * s - sign extend immediate 26462306a36Sopenharmony_ci * w - imm8 / imm32 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * OP: 000 ADD 100 AND 26762306a36Sopenharmony_ci * 001 OR 101 SUB 26862306a36Sopenharmony_ci * 010 ADC 110 XOR 26962306a36Sopenharmony_ci * 011 SBB 111 CMP 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* 64bit only */ 27362306a36Sopenharmony_ci if (!rex_w) 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* %rsp target only */ 27762306a36Sopenharmony_ci if (!rm_is_reg(CFI_SP)) 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci imm = ins.immediate.value; 28162306a36Sopenharmony_ci if (op1 & 2) { /* sign extend */ 28262306a36Sopenharmony_ci if (op1 & 1) { /* imm32 */ 28362306a36Sopenharmony_ci imm <<= 32; 28462306a36Sopenharmony_ci imm = (s64)imm >> 32; 28562306a36Sopenharmony_ci } else { /* imm8 */ 28662306a36Sopenharmony_ci imm <<= 56; 28762306a36Sopenharmony_ci imm = (s64)imm >> 56; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci switch (modrm_reg & 7) { 29262306a36Sopenharmony_ci case 5: 29362306a36Sopenharmony_ci imm = -imm; 29462306a36Sopenharmony_ci /* fallthrough */ 29562306a36Sopenharmony_ci case 0: 29662306a36Sopenharmony_ci /* add/sub imm, %rsp */ 29762306a36Sopenharmony_ci ADD_OP(op) { 29862306a36Sopenharmony_ci op->src.type = OP_SRC_ADD; 29962306a36Sopenharmony_ci op->src.reg = CFI_SP; 30062306a36Sopenharmony_ci op->src.offset = imm; 30162306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 30262306a36Sopenharmony_ci op->dest.reg = CFI_SP; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci case 4: 30762306a36Sopenharmony_ci /* and imm, %rsp */ 30862306a36Sopenharmony_ci ADD_OP(op) { 30962306a36Sopenharmony_ci op->src.type = OP_SRC_AND; 31062306a36Sopenharmony_ci op->src.reg = CFI_SP; 31162306a36Sopenharmony_ci op->src.offset = ins.immediate.value; 31262306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 31362306a36Sopenharmony_ci op->dest.reg = CFI_SP; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci default: 31862306a36Sopenharmony_ci /* WARN ? */ 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci break; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci case 0x89: 32562306a36Sopenharmony_ci if (!rex_w) 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (modrm_reg == CFI_SP) { 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (mod_is_reg()) { 33162306a36Sopenharmony_ci /* mov %rsp, reg */ 33262306a36Sopenharmony_ci ADD_OP(op) { 33362306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 33462306a36Sopenharmony_ci op->src.reg = CFI_SP; 33562306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 33662306a36Sopenharmony_ci op->dest.reg = modrm_rm; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci break; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci /* skip RIP relative displacement */ 34262306a36Sopenharmony_ci if (is_RIP()) 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* skip nontrivial SIB */ 34662306a36Sopenharmony_ci if (have_SIB()) { 34762306a36Sopenharmony_ci modrm_rm = sib_base; 34862306a36Sopenharmony_ci if (sib_index != CFI_SP) 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* mov %rsp, disp(%reg) */ 35362306a36Sopenharmony_ci ADD_OP(op) { 35462306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 35562306a36Sopenharmony_ci op->src.reg = CFI_SP; 35662306a36Sopenharmony_ci op->dest.type = OP_DEST_REG_INDIRECT; 35762306a36Sopenharmony_ci op->dest.reg = modrm_rm; 35862306a36Sopenharmony_ci op->dest.offset = ins.displacement.value; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (rm_is_reg(CFI_SP)) { 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* mov reg, %rsp */ 36962306a36Sopenharmony_ci ADD_OP(op) { 37062306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 37162306a36Sopenharmony_ci op->src.reg = modrm_reg; 37262306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 37362306a36Sopenharmony_ci op->dest.reg = CFI_SP; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* fallthrough */ 37962306a36Sopenharmony_ci case 0x88: 38062306a36Sopenharmony_ci if (!rex_w) 38162306a36Sopenharmony_ci break; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (rm_is_mem(CFI_BP)) { 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* mov reg, disp(%rbp) */ 38662306a36Sopenharmony_ci ADD_OP(op) { 38762306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 38862306a36Sopenharmony_ci op->src.reg = modrm_reg; 38962306a36Sopenharmony_ci op->dest.type = OP_DEST_REG_INDIRECT; 39062306a36Sopenharmony_ci op->dest.reg = CFI_BP; 39162306a36Sopenharmony_ci op->dest.offset = ins.displacement.value; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (rm_is_mem(CFI_SP)) { 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* mov reg, disp(%rsp) */ 39962306a36Sopenharmony_ci ADD_OP(op) { 40062306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 40162306a36Sopenharmony_ci op->src.reg = modrm_reg; 40262306a36Sopenharmony_ci op->dest.type = OP_DEST_REG_INDIRECT; 40362306a36Sopenharmony_ci op->dest.reg = CFI_SP; 40462306a36Sopenharmony_ci op->dest.offset = ins.displacement.value; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci case 0x8b: 41262306a36Sopenharmony_ci if (!rex_w) 41362306a36Sopenharmony_ci break; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (rm_is_mem(CFI_BP)) { 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* mov disp(%rbp), reg */ 41862306a36Sopenharmony_ci ADD_OP(op) { 41962306a36Sopenharmony_ci op->src.type = OP_SRC_REG_INDIRECT; 42062306a36Sopenharmony_ci op->src.reg = CFI_BP; 42162306a36Sopenharmony_ci op->src.offset = ins.displacement.value; 42262306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 42362306a36Sopenharmony_ci op->dest.reg = modrm_reg; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci break; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (rm_is_mem(CFI_SP)) { 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* mov disp(%rsp), reg */ 43162306a36Sopenharmony_ci ADD_OP(op) { 43262306a36Sopenharmony_ci op->src.type = OP_SRC_REG_INDIRECT; 43362306a36Sopenharmony_ci op->src.reg = CFI_SP; 43462306a36Sopenharmony_ci op->src.offset = ins.displacement.value; 43562306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 43662306a36Sopenharmony_ci op->dest.reg = modrm_reg; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci case 0x8d: 44462306a36Sopenharmony_ci if (mod_is_reg()) { 44562306a36Sopenharmony_ci WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset); 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* skip non 64bit ops */ 45062306a36Sopenharmony_ci if (!rex_w) 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* skip RIP relative displacement */ 45462306a36Sopenharmony_ci if (is_RIP()) 45562306a36Sopenharmony_ci break; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* skip nontrivial SIB */ 45862306a36Sopenharmony_ci if (have_SIB()) { 45962306a36Sopenharmony_ci modrm_rm = sib_base; 46062306a36Sopenharmony_ci if (sib_index != CFI_SP) 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* lea disp(%src), %dst */ 46562306a36Sopenharmony_ci ADD_OP(op) { 46662306a36Sopenharmony_ci op->src.offset = ins.displacement.value; 46762306a36Sopenharmony_ci if (!op->src.offset) { 46862306a36Sopenharmony_ci /* lea (%src), %dst */ 46962306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 47062306a36Sopenharmony_ci } else { 47162306a36Sopenharmony_ci /* lea disp(%src), %dst */ 47262306a36Sopenharmony_ci op->src.type = OP_SRC_ADD; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci op->src.reg = modrm_rm; 47562306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 47662306a36Sopenharmony_ci op->dest.reg = modrm_reg; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci case 0x8f: 48162306a36Sopenharmony_ci /* pop to mem */ 48262306a36Sopenharmony_ci ADD_OP(op) { 48362306a36Sopenharmony_ci op->src.type = OP_SRC_POP; 48462306a36Sopenharmony_ci op->dest.type = OP_DEST_MEM; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci case 0x90: 48962306a36Sopenharmony_ci insn->type = INSN_NOP; 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci case 0x9c: 49362306a36Sopenharmony_ci /* pushf */ 49462306a36Sopenharmony_ci ADD_OP(op) { 49562306a36Sopenharmony_ci op->src.type = OP_SRC_CONST; 49662306a36Sopenharmony_ci op->dest.type = OP_DEST_PUSHF; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci case 0x9d: 50162306a36Sopenharmony_ci /* popf */ 50262306a36Sopenharmony_ci ADD_OP(op) { 50362306a36Sopenharmony_ci op->src.type = OP_SRC_POPF; 50462306a36Sopenharmony_ci op->dest.type = OP_DEST_MEM; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci case 0x0f: 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (op2 == 0x01) { 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (modrm == 0xca) 51362306a36Sopenharmony_ci insn->type = INSN_CLAC; 51462306a36Sopenharmony_ci else if (modrm == 0xcb) 51562306a36Sopenharmony_ci insn->type = INSN_STAC; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci } else if (op2 >= 0x80 && op2 <= 0x8f) { 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci insn->type = INSN_JUMP_CONDITIONAL; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 || 52262306a36Sopenharmony_ci op2 == 0x35) { 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* sysenter, sysret */ 52562306a36Sopenharmony_ci insn->type = INSN_CONTEXT_SWITCH; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci } else if (op2 == 0x0b || op2 == 0xb9) { 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* ud2 */ 53062306a36Sopenharmony_ci insn->type = INSN_BUG; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci } else if (op2 == 0x0d || op2 == 0x1f) { 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* nopl/nopw */ 53562306a36Sopenharmony_ci insn->type = INSN_NOP; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci } else if (op2 == 0x1e) { 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb)) 54062306a36Sopenharmony_ci insn->type = INSN_ENDBR; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci } else if (op2 == 0x38 && op3 == 0xf8) { 54462306a36Sopenharmony_ci if (ins.prefixes.nbytes == 1 && 54562306a36Sopenharmony_ci ins.prefixes.bytes[0] == 0xf2) { 54662306a36Sopenharmony_ci /* ENQCMD cannot be used in the kernel. */ 54762306a36Sopenharmony_ci WARN("ENQCMD instruction at %s:%lx", sec->name, 54862306a36Sopenharmony_ci offset); 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci } else if (op2 == 0xa0 || op2 == 0xa8) { 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci /* push fs/gs */ 55462306a36Sopenharmony_ci ADD_OP(op) { 55562306a36Sopenharmony_ci op->src.type = OP_SRC_CONST; 55662306a36Sopenharmony_ci op->dest.type = OP_DEST_PUSH; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci } else if (op2 == 0xa1 || op2 == 0xa9) { 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* pop fs/gs */ 56262306a36Sopenharmony_ci ADD_OP(op) { 56362306a36Sopenharmony_ci op->src.type = OP_SRC_POP; 56462306a36Sopenharmony_ci op->dest.type = OP_DEST_MEM; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci case 0xc9: 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * leave 57362306a36Sopenharmony_ci * 57462306a36Sopenharmony_ci * equivalent to: 57562306a36Sopenharmony_ci * mov bp, sp 57662306a36Sopenharmony_ci * pop bp 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci ADD_OP(op) { 57962306a36Sopenharmony_ci op->src.type = OP_SRC_REG; 58062306a36Sopenharmony_ci op->src.reg = CFI_BP; 58162306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 58262306a36Sopenharmony_ci op->dest.reg = CFI_SP; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci ADD_OP(op) { 58562306a36Sopenharmony_ci op->src.type = OP_SRC_POP; 58662306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 58762306a36Sopenharmony_ci op->dest.reg = CFI_BP; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci case 0xcc: 59262306a36Sopenharmony_ci /* int3 */ 59362306a36Sopenharmony_ci insn->type = INSN_TRAP; 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci case 0xe3: 59762306a36Sopenharmony_ci /* jecxz/jrcxz */ 59862306a36Sopenharmony_ci insn->type = INSN_JUMP_CONDITIONAL; 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci case 0xe9: 60262306a36Sopenharmony_ci case 0xeb: 60362306a36Sopenharmony_ci insn->type = INSN_JUMP_UNCONDITIONAL; 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci case 0xc2: 60762306a36Sopenharmony_ci case 0xc3: 60862306a36Sopenharmony_ci insn->type = INSN_RETURN; 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci case 0xc7: /* mov imm, r/m */ 61262306a36Sopenharmony_ci if (!opts.noinstr) 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (ins.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) { 61662306a36Sopenharmony_ci struct reloc *immr, *disp; 61762306a36Sopenharmony_ci struct symbol *func; 61862306a36Sopenharmony_ci int idx; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci immr = find_reloc_by_dest(elf, (void *)sec, offset+3); 62162306a36Sopenharmony_ci disp = find_reloc_by_dest(elf, (void *)sec, offset+7); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (!immr || strcmp(immr->sym->name, "pv_ops")) 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci idx = (reloc_addend(immr) + 8) / sizeof(void *); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci func = disp->sym; 62962306a36Sopenharmony_ci if (disp->sym->type == STT_SECTION) 63062306a36Sopenharmony_ci func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp)); 63162306a36Sopenharmony_ci if (!func) { 63262306a36Sopenharmony_ci WARN("no func for pv_ops[]"); 63362306a36Sopenharmony_ci return -1; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci objtool_pv_add(file, idx, func); 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci case 0xcf: /* iret */ 64262306a36Sopenharmony_ci /* 64362306a36Sopenharmony_ci * Handle sync_core(), which has an IRET to self. 64462306a36Sopenharmony_ci * All other IRET are in STT_NONE entry code. 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_ci sym = find_symbol_containing(sec, offset); 64762306a36Sopenharmony_ci if (sym && sym->type == STT_FUNC) { 64862306a36Sopenharmony_ci ADD_OP(op) { 64962306a36Sopenharmony_ci /* add $40, %rsp */ 65062306a36Sopenharmony_ci op->src.type = OP_SRC_ADD; 65162306a36Sopenharmony_ci op->src.reg = CFI_SP; 65262306a36Sopenharmony_ci op->src.offset = 5*8; 65362306a36Sopenharmony_ci op->dest.type = OP_DEST_REG; 65462306a36Sopenharmony_ci op->dest.reg = CFI_SP; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* fallthrough */ 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci case 0xca: /* retf */ 66262306a36Sopenharmony_ci case 0xcb: /* retf */ 66362306a36Sopenharmony_ci insn->type = INSN_CONTEXT_SWITCH; 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci case 0xe0: /* loopne */ 66762306a36Sopenharmony_ci case 0xe1: /* loope */ 66862306a36Sopenharmony_ci case 0xe2: /* loop */ 66962306a36Sopenharmony_ci insn->type = INSN_JUMP_CONDITIONAL; 67062306a36Sopenharmony_ci break; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci case 0xe8: 67362306a36Sopenharmony_ci insn->type = INSN_CALL; 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * For the impact on the stack, a CALL behaves like 67662306a36Sopenharmony_ci * a PUSH of an immediate value (the return address). 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci ADD_OP(op) { 67962306a36Sopenharmony_ci op->src.type = OP_SRC_CONST; 68062306a36Sopenharmony_ci op->dest.type = OP_DEST_PUSH; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci case 0xfc: 68562306a36Sopenharmony_ci insn->type = INSN_CLD; 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci case 0xfd: 68962306a36Sopenharmony_ci insn->type = INSN_STD; 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci case 0xff: 69362306a36Sopenharmony_ci if (modrm_reg == 2 || modrm_reg == 3) { 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci insn->type = INSN_CALL_DYNAMIC; 69662306a36Sopenharmony_ci if (has_notrack_prefix(&ins)) 69762306a36Sopenharmony_ci WARN("notrack prefix found at %s:0x%lx", sec->name, offset); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci } else if (modrm_reg == 4) { 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci insn->type = INSN_JUMP_DYNAMIC; 70262306a36Sopenharmony_ci if (has_notrack_prefix(&ins)) 70362306a36Sopenharmony_ci WARN("notrack prefix found at %s:0x%lx", sec->name, offset); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci } else if (modrm_reg == 5) { 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* jmpf */ 70862306a36Sopenharmony_ci insn->type = INSN_CONTEXT_SWITCH; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci } else if (modrm_reg == 6) { 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* push from mem */ 71362306a36Sopenharmony_ci ADD_OP(op) { 71462306a36Sopenharmony_ci op->src.type = OP_SRC_CONST; 71562306a36Sopenharmony_ci op->dest.type = OP_DEST_PUSH; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci break; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci default: 72262306a36Sopenharmony_ci break; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci insn->immediate = ins.immediate.nbytes ? ins.immediate.value : 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return 0; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_civoid arch_initial_func_cfi_state(struct cfi_init_state *state) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci int i; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci for (i = 0; i < CFI_NUM_REGS; i++) { 73562306a36Sopenharmony_ci state->regs[i].base = CFI_UNDEFINED; 73662306a36Sopenharmony_ci state->regs[i].offset = 0; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* initial CFA (call frame address) */ 74062306a36Sopenharmony_ci state->cfa.base = CFI_SP; 74162306a36Sopenharmony_ci state->cfa.offset = 8; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* initial RA (return address) */ 74462306a36Sopenharmony_ci state->regs[CFI_RA].base = CFI_CFA; 74562306a36Sopenharmony_ci state->regs[CFI_RA].offset = -8; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ciconst char *arch_nop_insn(int len) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci static const char nops[5][5] = { 75162306a36Sopenharmony_ci { BYTES_NOP1 }, 75262306a36Sopenharmony_ci { BYTES_NOP2 }, 75362306a36Sopenharmony_ci { BYTES_NOP3 }, 75462306a36Sopenharmony_ci { BYTES_NOP4 }, 75562306a36Sopenharmony_ci { BYTES_NOP5 }, 75662306a36Sopenharmony_ci }; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (len < 1 || len > 5) { 75962306a36Sopenharmony_ci WARN("invalid NOP size: %d\n", len); 76062306a36Sopenharmony_ci return NULL; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci return nops[len-1]; 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci#define BYTE_RET 0xC3 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ciconst char *arch_ret_insn(int len) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci static const char ret[5][5] = { 77162306a36Sopenharmony_ci { BYTE_RET }, 77262306a36Sopenharmony_ci { BYTE_RET, 0xcc }, 77362306a36Sopenharmony_ci { BYTE_RET, 0xcc, BYTES_NOP1 }, 77462306a36Sopenharmony_ci { BYTE_RET, 0xcc, BYTES_NOP2 }, 77562306a36Sopenharmony_ci { BYTE_RET, 0xcc, BYTES_NOP3 }, 77662306a36Sopenharmony_ci }; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (len < 1 || len > 5) { 77962306a36Sopenharmony_ci WARN("invalid RET size: %d\n", len); 78062306a36Sopenharmony_ci return NULL; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return ret[len-1]; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ciint arch_decode_hint_reg(u8 sp_reg, int *base) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci switch (sp_reg) { 78962306a36Sopenharmony_ci case ORC_REG_UNDEFINED: 79062306a36Sopenharmony_ci *base = CFI_UNDEFINED; 79162306a36Sopenharmony_ci break; 79262306a36Sopenharmony_ci case ORC_REG_SP: 79362306a36Sopenharmony_ci *base = CFI_SP; 79462306a36Sopenharmony_ci break; 79562306a36Sopenharmony_ci case ORC_REG_BP: 79662306a36Sopenharmony_ci *base = CFI_BP; 79762306a36Sopenharmony_ci break; 79862306a36Sopenharmony_ci case ORC_REG_SP_INDIRECT: 79962306a36Sopenharmony_ci *base = CFI_SP_INDIRECT; 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci case ORC_REG_R10: 80262306a36Sopenharmony_ci *base = CFI_R10; 80362306a36Sopenharmony_ci break; 80462306a36Sopenharmony_ci case ORC_REG_R13: 80562306a36Sopenharmony_ci *base = CFI_R13; 80662306a36Sopenharmony_ci break; 80762306a36Sopenharmony_ci case ORC_REG_DI: 80862306a36Sopenharmony_ci *base = CFI_DI; 80962306a36Sopenharmony_ci break; 81062306a36Sopenharmony_ci case ORC_REG_DX: 81162306a36Sopenharmony_ci *base = CFI_DX; 81262306a36Sopenharmony_ci break; 81362306a36Sopenharmony_ci default: 81462306a36Sopenharmony_ci return -1; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return 0; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cibool arch_is_retpoline(struct symbol *sym) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci return !strncmp(sym->name, "__x86_indirect_", 15); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cibool arch_is_rethunk(struct symbol *sym) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci return !strcmp(sym->name, "__x86_return_thunk"); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cibool arch_is_embedded_insn(struct symbol *sym) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci return !strcmp(sym->name, "retbleed_return_thunk") || 83362306a36Sopenharmony_ci !strcmp(sym->name, "srso_safe_ret"); 83462306a36Sopenharmony_ci} 835