linux/tools/objtool/arch/x86/include/asm/insn.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2#ifndef _ASM_X86_INSN_H
   3#define _ASM_X86_INSN_H
   4/*
   5 * x86 instruction analysis
   6 *
   7 * Copyright (C) IBM Corporation, 2009
   8 */
   9
  10/* insn_attr_t is defined in inat.h */
  11#include <asm/inat.h>
  12
  13struct insn_field {
  14        union {
  15                insn_value_t value;
  16                insn_byte_t bytes[4];
  17        };
  18        /* !0 if we've run insn_get_xxx() for this field */
  19        unsigned char got;
  20        unsigned char nbytes;
  21};
  22
  23struct insn {
  24        struct insn_field prefixes;     /*
  25                                         * Prefixes
  26                                         * prefixes.bytes[3]: last prefix
  27                                         */
  28        struct insn_field rex_prefix;   /* REX prefix */
  29        struct insn_field vex_prefix;   /* VEX prefix */
  30        struct insn_field opcode;       /*
  31                                         * opcode.bytes[0]: opcode1
  32                                         * opcode.bytes[1]: opcode2
  33                                         * opcode.bytes[2]: opcode3
  34                                         */
  35        struct insn_field modrm;
  36        struct insn_field sib;
  37        struct insn_field displacement;
  38        union {
  39                struct insn_field immediate;
  40                struct insn_field moffset1;     /* for 64bit MOV */
  41                struct insn_field immediate1;   /* for 64bit imm or off16/32 */
  42        };
  43        union {
  44                struct insn_field moffset2;     /* for 64bit MOV */
  45                struct insn_field immediate2;   /* for 64bit imm or seg16 */
  46        };
  47
  48        insn_attr_t attr;
  49        unsigned char opnd_bytes;
  50        unsigned char addr_bytes;
  51        unsigned char length;
  52        unsigned char x86_64;
  53
  54        const insn_byte_t *kaddr;       /* kernel address of insn to analyze */
  55        const insn_byte_t *end_kaddr;   /* kernel address of last insn in buffer */
  56        const insn_byte_t *next_byte;
  57};
  58
  59#define MAX_INSN_SIZE   15
  60
  61#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6)
  62#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3)
  63#define X86_MODRM_RM(modrm) ((modrm) & 0x07)
  64
  65#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6)
  66#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
  67#define X86_SIB_BASE(sib) ((sib) & 0x07)
  68
  69#define X86_REX_W(rex) ((rex) & 8)
  70#define X86_REX_R(rex) ((rex) & 4)
  71#define X86_REX_X(rex) ((rex) & 2)
  72#define X86_REX_B(rex) ((rex) & 1)
  73
  74/* VEX bit flags  */
  75#define X86_VEX_W(vex)  ((vex) & 0x80)  /* VEX3 Byte2 */
  76#define X86_VEX_R(vex)  ((vex) & 0x80)  /* VEX2/3 Byte1 */
  77#define X86_VEX_X(vex)  ((vex) & 0x40)  /* VEX3 Byte1 */
  78#define X86_VEX_B(vex)  ((vex) & 0x20)  /* VEX3 Byte1 */
  79#define X86_VEX_L(vex)  ((vex) & 0x04)  /* VEX3 Byte2, VEX2 Byte1 */
  80/* VEX bit fields */
  81#define X86_EVEX_M(vex) ((vex) & 0x03)          /* EVEX Byte1 */
  82#define X86_VEX3_M(vex) ((vex) & 0x1f)          /* VEX3 Byte1 */
  83#define X86_VEX2_M      1                       /* VEX2.M always 1 */
  84#define X86_VEX_V(vex)  (((vex) & 0x78) >> 3)   /* VEX3 Byte2, VEX2 Byte1 */
  85#define X86_VEX_P(vex)  ((vex) & 0x03)          /* VEX3 Byte2, VEX2 Byte1 */
  86#define X86_VEX_M_MAX   0x1f                    /* VEX3.M Maximum value */
  87
  88extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64);
  89extern void insn_get_prefixes(struct insn *insn);
  90extern void insn_get_opcode(struct insn *insn);
  91extern void insn_get_modrm(struct insn *insn);
  92extern void insn_get_sib(struct insn *insn);
  93extern void insn_get_displacement(struct insn *insn);
  94extern void insn_get_immediate(struct insn *insn);
  95extern void insn_get_length(struct insn *insn);
  96
  97/* Attribute will be determined after getting ModRM (for opcode groups) */
  98static inline void insn_get_attribute(struct insn *insn)
  99{
 100        insn_get_modrm(insn);
 101}
 102
 103/* Instruction uses RIP-relative addressing */
 104extern int insn_rip_relative(struct insn *insn);
 105
 106/* Init insn for kernel text */
 107static inline void kernel_insn_init(struct insn *insn,
 108                                    const void *kaddr, int buf_len)
 109{
 110#ifdef CONFIG_X86_64
 111        insn_init(insn, kaddr, buf_len, 1);
 112#else /* CONFIG_X86_32 */
 113        insn_init(insn, kaddr, buf_len, 0);
 114#endif
 115}
 116
 117static inline int insn_is_avx(struct insn *insn)
 118{
 119        if (!insn->prefixes.got)
 120                insn_get_prefixes(insn);
 121        return (insn->vex_prefix.value != 0);
 122}
 123
 124static inline int insn_is_evex(struct insn *insn)
 125{
 126        if (!insn->prefixes.got)
 127                insn_get_prefixes(insn);
 128        return (insn->vex_prefix.nbytes == 4);
 129}
 130
 131/* Ensure this instruction is decoded completely */
 132static inline int insn_complete(struct insn *insn)
 133{
 134        return insn->opcode.got && insn->modrm.got && insn->sib.got &&
 135                insn->displacement.got && insn->immediate.got;
 136}
 137
 138static inline insn_byte_t insn_vex_m_bits(struct insn *insn)
 139{
 140        if (insn->vex_prefix.nbytes == 2)       /* 2 bytes VEX */
 141                return X86_VEX2_M;
 142        else if (insn->vex_prefix.nbytes == 3)  /* 3 bytes VEX */
 143                return X86_VEX3_M(insn->vex_prefix.bytes[1]);
 144        else                                    /* EVEX */
 145                return X86_EVEX_M(insn->vex_prefix.bytes[1]);
 146}
 147
 148static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
 149{
 150        if (insn->vex_prefix.nbytes == 2)       /* 2 bytes VEX */
 151                return X86_VEX_P(insn->vex_prefix.bytes[1]);
 152        else
 153                return X86_VEX_P(insn->vex_prefix.bytes[2]);
 154}
 155
 156/* Get the last prefix id from last prefix or VEX prefix */
 157static inline int insn_last_prefix_id(struct insn *insn)
 158{
 159        if (insn_is_avx(insn))
 160                return insn_vex_p_bits(insn);   /* VEX_p is a SIMD prefix id */
 161
 162        if (insn->prefixes.bytes[3])
 163                return inat_get_last_prefix_id(insn->prefixes.bytes[3]);
 164
 165        return 0;
 166}
 167
 168/* Offset of each field from kaddr */
 169static inline int insn_offset_rex_prefix(struct insn *insn)
 170{
 171        return insn->prefixes.nbytes;
 172}
 173static inline int insn_offset_vex_prefix(struct insn *insn)
 174{
 175        return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
 176}
 177static inline int insn_offset_opcode(struct insn *insn)
 178{
 179        return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes;
 180}
 181static inline int insn_offset_modrm(struct insn *insn)
 182{
 183        return insn_offset_opcode(insn) + insn->opcode.nbytes;
 184}
 185static inline int insn_offset_sib(struct insn *insn)
 186{
 187        return insn_offset_modrm(insn) + insn->modrm.nbytes;
 188}
 189static inline int insn_offset_displacement(struct insn *insn)
 190{
 191        return insn_offset_sib(insn) + insn->sib.nbytes;
 192}
 193static inline int insn_offset_immediate(struct insn *insn)
 194{
 195        return insn_offset_displacement(insn) + insn->displacement.nbytes;
 196}
 197
 198#define POP_SS_OPCODE 0x1f
 199#define MOV_SREG_OPCODE 0x8e
 200
 201/*
 202 * Intel SDM Vol.3A 6.8.3 states;
 203 * "Any single-step trap that would be delivered following the MOV to SS
 204 * instruction or POP to SS instruction (because EFLAGS.TF is 1) is
 205 * suppressed."
 206 * This function returns true if @insn is MOV SS or POP SS. On these
 207 * instructions, single stepping is suppressed.
 208 */
 209static inline int insn_masking_exception(struct insn *insn)
 210{
 211        return insn->opcode.bytes[0] == POP_SS_OPCODE ||
 212                (insn->opcode.bytes[0] == MOV_SREG_OPCODE &&
 213                 X86_MODRM_REG(insn->modrm.bytes[0]) == 2);
 214}
 215
 216#endif /* _ASM_X86_INSN_H */
 217