|
Packit |
b1f7ae |
/*
|
|
Packit |
b1f7ae |
* Copyright (c) 2013-2017, Intel Corporation
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
b1f7ae |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* * Redistributions of source code must retain the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer.
|
|
Packit |
b1f7ae |
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer in the documentation
|
|
Packit |
b1f7ae |
* and/or other materials provided with the distribution.
|
|
Packit |
b1f7ae |
* * Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
b1f7ae |
* may be used to endorse or promote products derived from this software
|
|
Packit |
b1f7ae |
* without specific prior written permission.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
b1f7ae |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
b1f7ae |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
b1f7ae |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit |
b1f7ae |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit |
b1f7ae |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit |
b1f7ae |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
b1f7ae |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
b1f7ae |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
b1f7ae |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
b1f7ae |
* POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "pt_ild.h"
|
|
Packit |
b1f7ae |
#include "pti-imm-defs.h"
|
|
Packit |
b1f7ae |
#include "pti-imm.h"
|
|
Packit |
b1f7ae |
#include "pti-modrm-defs.h"
|
|
Packit |
b1f7ae |
#include "pti-modrm.h"
|
|
Packit |
b1f7ae |
#include "pti-disp-defs.h"
|
|
Packit |
b1f7ae |
#include "pti-disp.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include <string.h>
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* SET UP 3 TABLES */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static uint8_t has_disp_regular[4][4][8];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void init_has_disp_regular_table(void)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t mod, rm;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
memset(has_disp_regular, 0, sizeof(has_disp_regular));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/*fill eamode16 */
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_16bit][0][6] = 2;
|
|
Packit |
b1f7ae |
for (rm = 0; rm < 8; rm++)
|
|
Packit |
b1f7ae |
for (mod = 1; mod <= 2; mod++)
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_16bit][mod][rm] = mod;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/*fill eamode32/64 */
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_32bit][0][5] = 4;
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_64bit][0][5] = 4;
|
|
Packit |
b1f7ae |
for (rm = 0; rm < 8; rm++) {
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_32bit][1][rm] = 1;
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_32bit][2][rm] = 4;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_64bit][1][rm] = 1;
|
|
Packit |
b1f7ae |
has_disp_regular[ptem_64bit][2][rm] = 4;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static uint8_t eamode_table[2][4];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void init_eamode_table(void)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
eamode_table[0][ptem_unknown] = ptem_unknown;
|
|
Packit |
b1f7ae |
eamode_table[0][ptem_16bit] = ptem_16bit;
|
|
Packit |
b1f7ae |
eamode_table[0][ptem_32bit] = ptem_32bit;
|
|
Packit |
b1f7ae |
eamode_table[0][ptem_64bit] = ptem_64bit;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
eamode_table[1][ptem_unknown] = ptem_unknown;
|
|
Packit |
b1f7ae |
eamode_table[1][ptem_16bit] = ptem_32bit;
|
|
Packit |
b1f7ae |
eamode_table[1][ptem_32bit] = ptem_16bit;
|
|
Packit |
b1f7ae |
eamode_table[1][ptem_64bit] = ptem_32bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static uint8_t has_sib_table[4][4][8];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void init_has_sib_table(void)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t mod;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
memset(has_sib_table, 0, sizeof(has_sib_table));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/*for eamode32/64 there is sib byte for mod!=3 and rm==4 */
|
|
Packit |
b1f7ae |
for (mod = 0; mod <= 2; mod++) {
|
|
Packit |
b1f7ae |
has_sib_table[ptem_32bit][mod][4] = 1;
|
|
Packit |
b1f7ae |
has_sib_table[ptem_64bit][mod][4] = 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* SOME ACCESSORS */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline uint8_t get_byte(const struct pt_ild *ild, uint8_t i)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return ild->itext[i];
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline uint8_t const *get_byte_ptr(const struct pt_ild *ild, uint8_t i)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return ild->itext + i;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int mode_64b(const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return ild->mode == ptem_64bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int mode_32b(const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return ild->mode == ptem_32bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int bits_match(uint8_t x, uint8_t mask, uint8_t target)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return (x & mask) == target;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline enum pt_exec_mode
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz_non64(const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (mode_32b(ild)) {
|
|
Packit |
b1f7ae |
if (ild->u.s.osz)
|
|
Packit |
b1f7ae |
return ptem_16bit;
|
|
Packit |
b1f7ae |
return ptem_32bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (ild->u.s.osz)
|
|
Packit |
b1f7ae |
return ptem_32bit;
|
|
Packit |
b1f7ae |
return ptem_16bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline enum pt_exec_mode
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz(const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (mode_64b(ild)) {
|
|
Packit |
b1f7ae |
if (ild->u.s.rex_w)
|
|
Packit |
b1f7ae |
return ptem_64bit;
|
|
Packit |
b1f7ae |
if (ild->u.s.osz)
|
|
Packit |
b1f7ae |
return ptem_16bit;
|
|
Packit |
b1f7ae |
return ptem_32bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return pti_get_nominal_eosz_non64(ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline enum pt_exec_mode
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz_df64(const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (mode_64b(ild)) {
|
|
Packit |
b1f7ae |
if (ild->u.s.rex_w)
|
|
Packit |
b1f7ae |
return ptem_64bit;
|
|
Packit |
b1f7ae |
if (ild->u.s.osz)
|
|
Packit |
b1f7ae |
return ptem_16bit;
|
|
Packit |
b1f7ae |
/* only this next line of code is different relative
|
|
Packit |
b1f7ae |
to pti_get_nominal_eosz(), above */
|
|
Packit |
b1f7ae |
return ptem_64bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return pti_get_nominal_eosz_non64(ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline enum pt_exec_mode
|
|
Packit |
b1f7ae |
pti_get_nominal_easz_non64(const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (mode_32b(ild)) {
|
|
Packit |
b1f7ae |
if (ild->u.s.asz)
|
|
Packit |
b1f7ae |
return ptem_16bit;
|
|
Packit |
b1f7ae |
return ptem_32bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (ild->u.s.asz)
|
|
Packit |
b1f7ae |
return ptem_32bit;
|
|
Packit |
b1f7ae |
return ptem_16bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline enum pt_exec_mode
|
|
Packit |
b1f7ae |
pti_get_nominal_easz(const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (mode_64b(ild)) {
|
|
Packit |
b1f7ae |
if (ild->u.s.asz)
|
|
Packit |
b1f7ae |
return ptem_32bit;
|
|
Packit |
b1f7ae |
return ptem_64bit;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return pti_get_nominal_easz_non64(ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int resolve_z(uint8_t *pbytes, enum pt_exec_mode eosz)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
static const uint8_t bytes[] = { 2, 4, 4 };
|
|
Packit |
b1f7ae |
unsigned int idx;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pbytes)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
idx = (unsigned int) eosz - 1;
|
|
Packit |
b1f7ae |
if (sizeof(bytes) <= idx)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*pbytes = bytes[idx];
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int resolve_v(uint8_t *pbytes, enum pt_exec_mode eosz)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
static const uint8_t bytes[] = { 2, 4, 8 };
|
|
Packit |
b1f7ae |
unsigned int idx;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pbytes)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
idx = (unsigned int) eosz - 1;
|
|
Packit |
b1f7ae |
if (sizeof(bytes) <= idx)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*pbytes = bytes[idx];
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* DECODERS */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int set_imm_bytes(struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
/*: set ild->imm1_bytes and ild->imm2_bytes for maps 0/1 */
|
|
Packit |
b1f7ae |
static uint8_t const *const map_map[] = {
|
|
Packit |
b1f7ae |
/* map 0 */ imm_bytes_map_0x0,
|
|
Packit |
b1f7ae |
/* map 1 */ imm_bytes_map_0x0F
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
uint8_t map, imm_code;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
map = ild->map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if ((sizeof(map_map) / sizeof(*map_map)) <= map)
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
imm_code = map_map[map][ild->nominal_opcode];
|
|
Packit |
b1f7ae |
switch (imm_code) {
|
|
Packit |
b1f7ae |
case PTI_IMM_NONE:
|
|
Packit |
b1f7ae |
case PTI_0_IMM_WIDTH_CONST_l2:
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_UIMM8_IMM_WIDTH_CONST_l2:
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_SIMM8_IMM_WIDTH_CONST_l2:
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2:
|
|
Packit |
b1f7ae |
/* SIMMz(eosz) */
|
|
Packit |
b1f7ae |
return resolve_z(&ild->imm1_bytes, pti_get_nominal_eosz(ild));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_UIMMv_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2:
|
|
Packit |
b1f7ae |
/* UIMMv(eosz) */
|
|
Packit |
b1f7ae |
return resolve_v(&ild->imm1_bytes, pti_get_nominal_eosz(ild));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_UIMM16_IMM_WIDTH_CONST_l2:
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 2;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_DF64_EOSZ_l2:
|
|
Packit |
b1f7ae |
/* push defaults to eosz64 in 64b mode, then uses SIMMz */
|
|
Packit |
b1f7ae |
return resolve_z(&ild->imm1_bytes,
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz_df64(ild));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf7_l1:
|
|
Packit |
b1f7ae |
if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2) {
|
|
Packit |
b1f7ae |
return resolve_z(&ild->imm1_bytes,
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz(ild));
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xc7_l1:
|
|
Packit |
b1f7ae |
if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 0) {
|
|
Packit |
b1f7ae |
return resolve_z(&ild->imm1_bytes,
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz(ild));
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf6_l1:
|
|
Packit |
b1f7ae |
if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2)
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_IMM_hasimm_map0x0_op0xc8_l1:
|
|
Packit |
b1f7ae |
if (ild->map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
/*enter -> imm1=2, imm2=1 */
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 2;
|
|
Packit |
b1f7ae |
ild->imm2_bytes = 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_IMM_hasimm_map0x0F_op0x78_l1:
|
|
Packit |
b1f7ae |
/* AMD SSE4a (insertq/extrq use osz/f2) vs vmread
|
|
Packit |
b1f7ae |
* (no prefixes)
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (ild->map == PTI_MAP_1) {
|
|
Packit |
b1f7ae |
if (ild->u.s.osz || ild->u.s.last_f2f3 == 2) {
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
ild->imm2_bytes = 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int imm_dec(struct pt_ild *ild, uint8_t length)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (ild->map == PTI_MAP_AMD3DNOW) {
|
|
Packit |
b1f7ae |
if (ild->max_bytes <= length)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->nominal_opcode = get_byte(ild, length);
|
|
Packit |
b1f7ae |
return length + 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = set_imm_bytes(ild);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
length += ild->imm1_bytes;
|
|
Packit |
b1f7ae |
length += ild->imm2_bytes;
|
|
Packit |
b1f7ae |
if (ild->max_bytes < length)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return length;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int compute_disp_dec(struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
/* set ild->disp_bytes for maps 0 and 1. */
|
|
Packit |
b1f7ae |
static uint8_t const *const map_map[] = {
|
|
Packit |
b1f7ae |
/* map 0 */ disp_bytes_map_0x0,
|
|
Packit |
b1f7ae |
/* map 1 */ disp_bytes_map_0x0F
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
uint8_t map, disp_kind;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (0 < ild->disp_bytes)
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
map = ild->map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if ((sizeof(map_map) / sizeof(*map_map)) <= map)
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
disp_kind = map_map[map][ild->nominal_opcode];
|
|
Packit |
b1f7ae |
switch (disp_kind) {
|
|
Packit |
b1f7ae |
case PTI_DISP_NONE:
|
|
Packit |
b1f7ae |
ild->disp_bytes = 0;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_PRESERVE_DEFAULT:
|
|
Packit |
b1f7ae |
/* nothing to do */
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_BRDISP8:
|
|
Packit |
b1f7ae |
ild->disp_bytes = 1;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_DISP_BUCKET_0_l1:
|
|
Packit |
b1f7ae |
/* BRDISPz(eosz) for 16/32 modes, and BRDISP32 for 64b mode */
|
|
Packit |
b1f7ae |
if (mode_64b(ild)) {
|
|
Packit |
b1f7ae |
ild->disp_bytes = 4;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return resolve_z(&ild->disp_bytes,
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz(ild));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_MEMDISPv_DISP_WIDTH_ASZ_NONTERM_EASZ_l2:
|
|
Packit |
b1f7ae |
/* MEMDISPv(easz) */
|
|
Packit |
b1f7ae |
return resolve_v(&ild->disp_bytes, pti_get_nominal_easz(ild));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2:
|
|
Packit |
b1f7ae |
/* BRDISPz(eosz) for 16/32/64 modes */
|
|
Packit |
b1f7ae |
return resolve_z(&ild->disp_bytes, pti_get_nominal_eosz(ild));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case PTI_RESOLVE_BYREG_DISP_map0x0_op0xc7_l1:
|
|
Packit |
b1f7ae |
/* reg=0 -> preserve, reg=7 -> BRDISPz(eosz) */
|
|
Packit |
b1f7ae |
if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 7) {
|
|
Packit |
b1f7ae |
return resolve_z(&ild->disp_bytes,
|
|
Packit |
b1f7ae |
pti_get_nominal_eosz(ild));
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int disp_dec(struct pt_ild *ild, uint8_t length)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t disp_bytes;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = compute_disp_dec(ild);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
disp_bytes = ild->disp_bytes;
|
|
Packit |
b1f7ae |
if (disp_bytes == 0)
|
|
Packit |
b1f7ae |
return imm_dec(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (length + disp_bytes > ild->max_bytes)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/*Record only position; must be able to re-read itext bytes for actual
|
|
Packit |
b1f7ae |
value. (SMC/CMC issue). */
|
|
Packit |
b1f7ae |
ild->disp_pos = length;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return imm_dec(ild, length + disp_bytes);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int sib_dec(struct pt_ild *ild, uint8_t length)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t sib;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (ild->max_bytes <= length)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
sib = get_byte(ild, length);
|
|
Packit |
b1f7ae |
if ((sib & 0x07) == 0x05 && pti_get_modrm_mod(ild) == 0)
|
|
Packit |
b1f7ae |
ild->disp_bytes = 4;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return disp_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int modrm_dec(struct pt_ild *ild, uint8_t length)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
static uint8_t const *const has_modrm_2d[2] = {
|
|
Packit |
b1f7ae |
has_modrm_map_0x0,
|
|
Packit |
b1f7ae |
has_modrm_map_0x0F
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
int has_modrm = PTI_MODRM_FALSE;
|
|
Packit |
b1f7ae |
pti_map_enum_t map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
map = pti_get_map(ild);
|
|
Packit |
b1f7ae |
if (map >= PTI_MAP_2)
|
|
Packit |
b1f7ae |
has_modrm = PTI_MODRM_TRUE;
|
|
Packit |
b1f7ae |
else
|
|
Packit |
b1f7ae |
has_modrm = has_modrm_2d[map][ild->nominal_opcode];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (has_modrm == PTI_MODRM_FALSE || has_modrm == PTI_MODRM_UNDEF)
|
|
Packit |
b1f7ae |
return disp_dec(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* really >= here because we have not eaten the byte yet */
|
|
Packit |
b1f7ae |
if (length >= ild->max_bytes)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->modrm_byte = get_byte(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (has_modrm != PTI_MODRM_IGNORE_MOD) {
|
|
Packit |
b1f7ae |
/* set disp_bytes and sib using simple tables */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
uint8_t eamode = eamode_table[ild->u.s.asz][ild->mode];
|
|
Packit |
b1f7ae |
uint8_t mod = (uint8_t) pti_get_modrm_mod(ild);
|
|
Packit |
b1f7ae |
uint8_t rm = (uint8_t) pti_get_modrm_rm(ild);
|
|
Packit |
b1f7ae |
uint8_t has_sib;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->disp_bytes = has_disp_regular[eamode][mod][rm];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
has_sib = has_sib_table[eamode][mod][rm];
|
|
Packit |
b1f7ae |
if (has_sib)
|
|
Packit |
b1f7ae |
return sib_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return disp_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int get_next_as_opcode(struct pt_ild *ild, uint8_t length)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (ild->max_bytes <= length)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->nominal_opcode = get_byte(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return modrm_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int opcode_dec(struct pt_ild *ild, uint8_t length)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t b, m;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/*no need to check max_bytes - it was checked in previous scanners */
|
|
Packit |
b1f7ae |
b = get_byte(ild, length);
|
|
Packit |
b1f7ae |
if (b != 0x0F) { /* 1B opcodes, map 0 */
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_0;
|
|
Packit |
b1f7ae |
ild->nominal_opcode = b;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return modrm_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
length++; /* eat the 0x0F */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (ild->max_bytes <= length)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* 0x0F opcodes MAPS 1,2,3 */
|
|
Packit |
b1f7ae |
m = get_byte(ild, length);
|
|
Packit |
b1f7ae |
if (m == 0x38) {
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_2;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return get_next_as_opcode(ild, length + 1);
|
|
Packit |
b1f7ae |
} else if (m == 0x3A) {
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_3;
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return get_next_as_opcode(ild, length + 1);
|
|
Packit |
b1f7ae |
} else if (bits_match(m, 0xf8, 0x38)) {
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_INVALID;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return get_next_as_opcode(ild, length + 1);
|
|
Packit |
b1f7ae |
} else if (m == 0x0F) { /* 3dNow */
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_AMD3DNOW;
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
/* real opcode is in immediate later on, but we need an
|
|
Packit |
b1f7ae |
* opcode now. */
|
|
Packit |
b1f7ae |
ild->nominal_opcode = 0x0F;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return modrm_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
} else { /* map 1 (simple two byte opcodes) */
|
|
Packit |
b1f7ae |
ild->nominal_opcode = m;
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return modrm_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
typedef int (*prefix_decoder)(struct pt_ild *ild, uint8_t length, uint8_t rex);
|
|
Packit |
b1f7ae |
static prefix_decoder prefix_table[256];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int prefix_decode(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t byte;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (ild->max_bytes <= length)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
byte = get_byte(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return prefix_table[byte](ild, length, rex);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int prefix_next(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return prefix_decode(ild, length + 1, rex);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_osz(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.osz = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return prefix_next(ild, length, 0);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_asz(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.asz = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return prefix_next(ild, length, 0);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_lock(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.lock = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return prefix_next(ild, length, 0);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_f2(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.f2 = 1;
|
|
Packit |
b1f7ae |
ild->u.s.last_f2f3 = 2;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return prefix_next(ild, length, 0);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_f3(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.f3 = 1;
|
|
Packit |
b1f7ae |
ild->u.s.last_f2f3 = 3;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return prefix_next(ild, length, 0);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_ignore(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return prefix_next(ild, length, 0);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_done(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (rex & 0x04)
|
|
Packit |
b1f7ae |
ild->u.s.rex_r = 1;
|
|
Packit |
b1f7ae |
if (rex & 0x08)
|
|
Packit |
b1f7ae |
ild->u.s.rex_w = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return opcode_dec(ild, length);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_rex(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (mode_64b(ild))
|
|
Packit |
b1f7ae |
return prefix_next(ild, length, get_byte(ild, length));
|
|
Packit |
b1f7ae |
else
|
|
Packit |
b1f7ae |
return opcode_dec(ild, length);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static inline int prefix_vex_done(struct pt_ild *ild, uint8_t length)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->nominal_opcode = get_byte(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return modrm_dec(ild, length + 1);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_vex_c5(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t max_bytes;
|
|
Packit |
b1f7ae |
uint8_t p1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
max_bytes = ild->max_bytes;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Read the next byte to validate that this is indeed VEX. */
|
|
Packit |
b1f7ae |
if (max_bytes <= (length + 1))
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
p1 = get_byte(ild, length + 1);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If p1[7:6] is not 11b in non-64-bit mode, this is LDS, not VEX. */
|
|
Packit |
b1f7ae |
if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
|
|
Packit |
b1f7ae |
return opcode_dec(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We need at least 3 bytes
|
|
Packit |
b1f7ae |
* - 2 for the VEX prefix and payload and
|
|
Packit |
b1f7ae |
* - 1 for the opcode.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (max_bytes < (length + 3))
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.vex = 1;
|
|
Packit |
b1f7ae |
if (p1 & 0x80)
|
|
Packit |
b1f7ae |
ild->u.s.rex_r = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Eat the VEX. */
|
|
Packit |
b1f7ae |
length += 2;
|
|
Packit |
b1f7ae |
return prefix_vex_done(ild, length);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_vex_c4(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t max_bytes;
|
|
Packit |
b1f7ae |
uint8_t p1, p2, map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
max_bytes = ild->max_bytes;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Read the next byte to validate that this is indeed VEX. */
|
|
Packit |
b1f7ae |
if (max_bytes <= (length + 1))
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
p1 = get_byte(ild, length + 1);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If p1[7:6] is not 11b in non-64-bit mode, this is LES, not VEX. */
|
|
Packit |
b1f7ae |
if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
|
|
Packit |
b1f7ae |
return opcode_dec(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We need at least 4 bytes
|
|
Packit |
b1f7ae |
* - 3 for the VEX prefix and payload and
|
|
Packit |
b1f7ae |
* - 1 for the opcode.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (max_bytes < (length + 4))
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
p2 = get_byte(ild, length + 2);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.vex = 1;
|
|
Packit |
b1f7ae |
if (p1 & 0x80)
|
|
Packit |
b1f7ae |
ild->u.s.rex_r = 1;
|
|
Packit |
b1f7ae |
if (p2 & 0x80)
|
|
Packit |
b1f7ae |
ild->u.s.rex_w = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
map = p1 & 0x1f;
|
|
Packit |
b1f7ae |
if (PTI_MAP_INVALID <= map)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->map = map;
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_3)
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Eat the VEX. */
|
|
Packit |
b1f7ae |
length += 3;
|
|
Packit |
b1f7ae |
return prefix_vex_done(ild, length);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int prefix_evex(struct pt_ild *ild, uint8_t length, uint8_t rex)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t max_bytes;
|
|
Packit |
b1f7ae |
uint8_t p1, p2, map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
(void) rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
max_bytes = ild->max_bytes;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Read the next byte to validate that this is indeed EVEX. */
|
|
Packit |
b1f7ae |
if (max_bytes <= (length + 1))
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
p1 = get_byte(ild, length + 1);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If p1[7:6] is not 11b in non-64-bit mode, this is BOUND, not EVEX. */
|
|
Packit |
b1f7ae |
if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
|
|
Packit |
b1f7ae |
return opcode_dec(ild, length);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We need at least 5 bytes
|
|
Packit |
b1f7ae |
* - 4 for the EVEX prefix and payload and
|
|
Packit |
b1f7ae |
* - 1 for the opcode.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (max_bytes < (length + 5))
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
p2 = get_byte(ild, length + 2);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.s.vex = 1;
|
|
Packit |
b1f7ae |
if (p1 & 0x80)
|
|
Packit |
b1f7ae |
ild->u.s.rex_r = 1;
|
|
Packit |
b1f7ae |
if (p2 & 0x80)
|
|
Packit |
b1f7ae |
ild->u.s.rex_w = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
map = p1 & 0x03;
|
|
Packit |
b1f7ae |
ild->map = map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_3)
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Eat the EVEX. */
|
|
Packit |
b1f7ae |
length += 4;
|
|
Packit |
b1f7ae |
return prefix_vex_done(ild, length);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void init_prefix_table(void)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
unsigned int byte;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (byte = 0; byte <= 0xff; ++byte)
|
|
Packit |
b1f7ae |
prefix_table[byte] = prefix_done;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
prefix_table[0x66] = prefix_osz;
|
|
Packit |
b1f7ae |
prefix_table[0x67] = prefix_asz;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Segment prefixes. */
|
|
Packit |
b1f7ae |
prefix_table[0x2e] = prefix_ignore;
|
|
Packit |
b1f7ae |
prefix_table[0x3e] = prefix_ignore;
|
|
Packit |
b1f7ae |
prefix_table[0x26] = prefix_ignore;
|
|
Packit |
b1f7ae |
prefix_table[0x36] = prefix_ignore;
|
|
Packit |
b1f7ae |
prefix_table[0x64] = prefix_ignore;
|
|
Packit |
b1f7ae |
prefix_table[0x65] = prefix_ignore;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
prefix_table[0xf0] = prefix_lock;
|
|
Packit |
b1f7ae |
prefix_table[0xf2] = prefix_f2;
|
|
Packit |
b1f7ae |
prefix_table[0xf3] = prefix_f3;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (byte = 0x40; byte <= 0x4f; ++byte)
|
|
Packit |
b1f7ae |
prefix_table[byte] = prefix_rex;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
prefix_table[0xc4] = prefix_vex_c4;
|
|
Packit |
b1f7ae |
prefix_table[0xc5] = prefix_vex_c5;
|
|
Packit |
b1f7ae |
prefix_table[0x62] = prefix_evex;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int decode(struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
return prefix_decode(ild, 0, 0);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int set_branch_target(struct pt_insn_ext *iext, const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!iext || !ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iext->variant.branch.is_direct = 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (ild->disp_bytes == 1) {
|
|
Packit |
b1f7ae |
int8_t *b = (int8_t *) (get_byte_ptr(ild, ild->disp_pos));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iext->variant.branch.displacement = *b;
|
|
Packit |
b1f7ae |
} else if (ild->disp_bytes == 2) {
|
|
Packit |
b1f7ae |
int16_t *w = (int16_t *) (get_byte_ptr(ild, ild->disp_pos));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iext->variant.branch.displacement = *w;
|
|
Packit |
b1f7ae |
} else if (ild->disp_bytes == 4) {
|
|
Packit |
b1f7ae |
int32_t *d = (int32_t *) (get_byte_ptr(ild, ild->disp_pos));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iext->variant.branch.displacement = *d;
|
|
Packit |
b1f7ae |
} else
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* MAIN ENTRY POINTS */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
void pt_ild_init(void)
|
|
Packit |
b1f7ae |
{ /* initialization */
|
|
Packit |
b1f7ae |
init_has_disp_regular_table();
|
|
Packit |
b1f7ae |
init_has_sib_table();
|
|
Packit |
b1f7ae |
init_eamode_table();
|
|
Packit |
b1f7ae |
init_prefix_table();
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int pt_instruction_length_decode(struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild->u.i = 0;
|
|
Packit |
b1f7ae |
ild->imm1_bytes = 0;
|
|
Packit |
b1f7ae |
ild->imm2_bytes = 0;
|
|
Packit |
b1f7ae |
ild->disp_bytes = 0;
|
|
Packit |
b1f7ae |
ild->modrm_byte = 0;
|
|
Packit |
b1f7ae |
ild->map = PTI_MAP_INVALID;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ild->mode)
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return decode(ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int pt_instruction_decode(struct pt_insn *insn, struct pt_insn_ext *iext,
|
|
Packit |
b1f7ae |
const struct pt_ild *ild)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t opcode, map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!iext || !ild)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_INVALID;
|
|
Packit |
b1f7ae |
memset(&iext->variant, 0, sizeof(iext->variant));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
insn->iclass = ptic_other;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
opcode = ild->nominal_opcode;
|
|
Packit |
b1f7ae |
map = ild->map;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (map > PTI_MAP_1)
|
|
Packit |
b1f7ae |
return 0; /* uninteresting */
|
|
Packit |
b1f7ae |
if (ild->u.s.vex)
|
|
Packit |
b1f7ae |
return 0; /* uninteresting */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* PTI_INST_JCC, 70...7F, 0F (0x80...0x8F) */
|
|
Packit |
b1f7ae |
if (opcode >= 0x70 && opcode <= 0x7F) {
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_cond_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JCC;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (opcode >= 0x80 && opcode <= 0x8F) {
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_cond_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JCC;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
switch (ild->nominal_opcode) {
|
|
Packit |
b1f7ae |
case 0x9A:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_CALL_9A;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xFF:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
uint8_t reg = pti_get_modrm_reg(ild);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (reg == 2) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_CALL_FFr2;
|
|
Packit |
b1f7ae |
} else if (reg == 3) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_CALL_FFr3;
|
|
Packit |
b1f7ae |
} else if (reg == 4) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JMP_FFr4;
|
|
Packit |
b1f7ae |
} else if (reg == 5) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JMP_FFr5;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xE8:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_CALL_E8;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xCD:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_INT;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xCC:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_INT3;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xCE:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_INTO;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xF1:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_INT1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xCF:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_IRET;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xE9:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JMP_E9;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xEA:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
/* Far jumps are treated as indirect jumps. */
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JMP_EA;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xEB:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JMP_EB;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xE3:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_cond_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_JrCXZ;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xE0:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_cond_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_LOOPNE;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xE1:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_cond_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_LOOPE;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xE2:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_cond_jump;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_LOOP;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return set_branch_target(iext, ild);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0x22:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1)
|
|
Packit |
b1f7ae |
if (pti_get_modrm_reg(ild) == 3)
|
|
Packit |
b1f7ae |
if (!ild->u.s.rex_r)
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_MOV_CR3;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xC3:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_RET_C3;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xC2:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_RET_C2;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xCB:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_RET_CB;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xCA:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_0) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_RET_CA;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0x05:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_SYSCALL;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0x34:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_SYSENTER;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0x35:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_SYSEXIT;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0x07:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1) {
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_SYSRET;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0x01:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1) {
|
|
Packit |
b1f7ae |
switch (ild->modrm_byte) {
|
|
Packit |
b1f7ae |
case 0xc1:
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_call;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_VMCALL;
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xc2:
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_VMLAUNCH;
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xc3:
|
|
Packit |
b1f7ae |
insn->iclass = ptic_far_return;
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_VMRESUME;
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case 0xc7:
|
|
Packit |
b1f7ae |
if (map == PTI_MAP_1 &&
|
|
Packit |
b1f7ae |
pti_get_modrm_mod(ild) != 3 &&
|
|
Packit |
b1f7ae |
pti_get_modrm_reg(ild) == 6)
|
|
Packit |
b1f7ae |
iext->iclass = PTI_INST_VMPTRLD;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
int pt_ild_decode(struct pt_insn *insn, struct pt_insn_ext *iext)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_ild ild;
|
|
Packit |
b1f7ae |
int size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!insn || !iext)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ild.mode = insn->mode;
|
|
Packit |
b1f7ae |
ild.itext = insn->raw;
|
|
Packit |
b1f7ae |
ild.max_bytes = insn->size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
size = pt_instruction_length_decode(&ild);
|
|
Packit |
b1f7ae |
if (size < 0)
|
|
Packit |
b1f7ae |
return size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
insn->size = (uint8_t) size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return pt_instruction_decode(insn, iext, &ild);
|
|
Packit |
b1f7ae |
}
|