linux/arch/x86/mm/kmemcheck/opcode.c
<<
>>
Prefs
   1#include <linux/types.h>
   2
   3#include "opcode.h"
   4
   5static bool opcode_is_prefix(uint8_t b)
   6{
   7        return
   8                /* Group 1 */
   9                b == 0xf0 || b == 0xf2 || b == 0xf3
  10                /* Group 2 */
  11                || b == 0x2e || b == 0x36 || b == 0x3e || b == 0x26
  12                || b == 0x64 || b == 0x65
  13                /* Group 3 */
  14                || b == 0x66
  15                /* Group 4 */
  16                || b == 0x67;
  17}
  18
  19#ifdef CONFIG_X86_64
  20static bool opcode_is_rex_prefix(uint8_t b)
  21{
  22        return (b & 0xf0) == 0x40;
  23}
  24#else
  25static bool opcode_is_rex_prefix(uint8_t b)
  26{
  27        return false;
  28}
  29#endif
  30
  31#define REX_W (1 << 3)
  32
  33/*
  34 * This is a VERY crude opcode decoder. We only need to find the size of the
  35 * load/store that caused our #PF and this should work for all the opcodes
  36 * that we care about. Moreover, the ones who invented this instruction set
  37 * should be shot.
  38 */
  39void kmemcheck_opcode_decode(const uint8_t *op, unsigned int *size)
  40{
  41        /* Default operand size */
  42        int operand_size_override = 4;
  43
  44        /* prefixes */
  45        for (; opcode_is_prefix(*op); ++op) {
  46                if (*op == 0x66)
  47                        operand_size_override = 2;
  48        }
  49
  50        /* REX prefix */
  51        if (opcode_is_rex_prefix(*op)) {
  52                uint8_t rex = *op;
  53
  54                ++op;
  55                if (rex & REX_W) {
  56                        switch (*op) {
  57                        case 0x63:
  58                                *size = 4;
  59                                return;
  60                        case 0x0f:
  61                                ++op;
  62
  63                                switch (*op) {
  64                                case 0xb6:
  65                                case 0xbe:
  66                                        *size = 1;
  67                                        return;
  68                                case 0xb7:
  69                                case 0xbf:
  70                                        *size = 2;
  71                                        return;
  72                                }
  73
  74                                break;
  75                        }
  76
  77                        *size = 8;
  78                        return;
  79                }
  80        }
  81
  82        /* escape opcode */
  83        if (*op == 0x0f) {
  84                ++op;
  85
  86                /*
  87                 * This is move with zero-extend and sign-extend, respectively;
  88                 * we don't have to think about 0xb6/0xbe, because this is
  89                 * already handled in the conditional below.
  90                 */
  91                if (*op == 0xb7 || *op == 0xbf)
  92                        operand_size_override = 2;
  93        }
  94
  95        *size = (*op & 1) ? operand_size_override : 1;
  96}
  97
  98const uint8_t *kmemcheck_opcode_get_primary(const uint8_t *op)
  99{
 100        /* skip prefixes */
 101        while (opcode_is_prefix(*op))
 102                ++op;
 103        if (opcode_is_rex_prefix(*op))
 104                ++op;
 105        return op;
 106}
 107