perf tools: Add Intel PT instruction decoder
Add support for decoding instructions for Intel Processor Trace. The kernel x86 instruction decoder is copied for this. This essentially provides intel_pt_get_insn() which takes a binary buffer, uses the kernel's x86 instruction decoder to get details of the instruction and then categorizes it for consumption by an Intel PT decoder. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Cc: Jiri Olsa <jolsa@redhat.com> Link: http://lkml.kernel.org/r/1439450095-30122-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Родитель
a4e925905c
Коммит
237fae79f5
|
@ -57,6 +57,8 @@ quiet_cmd_cc_i_c = CPP $@
|
|||
quiet_cmd_cc_s_c = AS $@
|
||||
cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $<
|
||||
|
||||
quiet_cmd_gen = GEN $@
|
||||
|
||||
# Link agregate command
|
||||
# If there's nothing to link, create empty $@ object.
|
||||
quiet_cmd_ld_multi = LD $@
|
||||
|
|
|
@ -29,3 +29,4 @@ config.mak.autogen
|
|||
*.pyc
|
||||
*.pyo
|
||||
.config-detected
|
||||
util/intel-pt-decoder/inat-tables.c
|
||||
|
|
|
@ -76,6 +76,12 @@ include config/utilities.mak
|
|||
#
|
||||
# Define NO_AUXTRACE if you do not want AUX area tracing support
|
||||
|
||||
# As per kernel Makefile, avoid funny character set dependencies
|
||||
unexport LC_ALL
|
||||
LC_COLLATE=C
|
||||
LC_NUMERIC=C
|
||||
export LC_COLLATE LC_NUMERIC
|
||||
|
||||
ifeq ($(srctree),)
|
||||
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
|
||||
srctree := $(patsubst %/,%,$(dir $(srctree)))
|
||||
|
@ -135,6 +141,7 @@ INSTALL = install
|
|||
FLEX = flex
|
||||
BISON = bison
|
||||
STRIP = strip
|
||||
AWK = awk
|
||||
|
||||
LIB_DIR = $(srctree)/tools/lib/api/
|
||||
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
|
||||
|
@ -289,7 +296,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf
|
|||
|
||||
PERF_IN := $(OUTPUT)perf-in.o
|
||||
|
||||
export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX
|
||||
export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK
|
||||
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
|
||||
|
||||
$(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE
|
||||
|
@ -565,7 +572,8 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
|
|||
$(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
|
||||
$(Q)$(RM) $(OUTPUT).config-detected
|
||||
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
|
||||
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
|
||||
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
|
||||
$(OUTPUT)util/intel-pt-decoder/inat-tables.c
|
||||
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
|
||||
$(python-clean)
|
||||
|
||||
|
|
|
@ -1 +1,11 @@
|
|||
libperf-$(CONFIG_AUXTRACE) += intel-pt-pkt-decoder.o
|
||||
libperf-$(CONFIG_AUXTRACE) += intel-pt-pkt-decoder.o intel-pt-insn-decoder.o
|
||||
|
||||
inat_tables_script = util/intel-pt-decoder/gen-insn-attr-x86.awk
|
||||
inat_tables_maps = util/intel-pt-decoder/x86-opcode-map.txt
|
||||
|
||||
$(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_tables_maps)
|
||||
@$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ || rm -f $@
|
||||
|
||||
$(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/inat.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c
|
||||
|
||||
CFLAGS_intel-pt-insn-decoder.o += -I$(OUTPUT)util/intel-pt-decoder -Wno-override-init
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
#!/bin/awk -f
|
||||
# gen-insn-attr-x86.awk: Instruction attribute table generator
|
||||
# Written by Masami Hiramatsu <mhiramat@redhat.com>
|
||||
#
|
||||
# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c
|
||||
|
||||
# Awk implementation sanity check
|
||||
function check_awk_implement() {
|
||||
if (sprintf("%x", 0) != "0")
|
||||
return "Your awk has a printf-format problem."
|
||||
return ""
|
||||
}
|
||||
|
||||
# Clear working vars
|
||||
function clear_vars() {
|
||||
delete table
|
||||
delete lptable2
|
||||
delete lptable1
|
||||
delete lptable3
|
||||
eid = -1 # escape id
|
||||
gid = -1 # group id
|
||||
aid = -1 # AVX id
|
||||
tname = ""
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
# Implementation error checking
|
||||
awkchecked = check_awk_implement()
|
||||
if (awkchecked != "") {
|
||||
print "Error: " awkchecked > "/dev/stderr"
|
||||
print "Please try to use gawk." > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Setup generating tables
|
||||
print "/* x86 opcode map generated from x86-opcode-map.txt */"
|
||||
print "/* Do not change this code. */\n"
|
||||
ggid = 1
|
||||
geid = 1
|
||||
gaid = 0
|
||||
delete etable
|
||||
delete gtable
|
||||
delete atable
|
||||
|
||||
opnd_expr = "^[A-Za-z/]"
|
||||
ext_expr = "^\\("
|
||||
sep_expr = "^\\|$"
|
||||
group_expr = "^Grp[0-9A-Za-z]+"
|
||||
|
||||
imm_expr = "^[IJAOL][a-z]"
|
||||
imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
|
||||
imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
|
||||
imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)"
|
||||
imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)"
|
||||
imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)"
|
||||
imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)"
|
||||
imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
|
||||
imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)"
|
||||
imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)"
|
||||
imm_flag["Ob"] = "INAT_MOFFSET"
|
||||
imm_flag["Ov"] = "INAT_MOFFSET"
|
||||
imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)"
|
||||
|
||||
modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])"
|
||||
force64_expr = "\\([df]64\\)"
|
||||
rex_expr = "^REX(\\.[XRWB]+)*"
|
||||
fpu_expr = "^ESC" # TODO
|
||||
|
||||
lprefix1_expr = "\\((66|!F3)\\)"
|
||||
lprefix2_expr = "\\(F3\\)"
|
||||
lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)"
|
||||
lprefix_expr = "\\((66|F2|F3)\\)"
|
||||
max_lprefix = 4
|
||||
|
||||
# All opcodes starting with lower-case 'v' or with (v1) superscript
|
||||
# accepts VEX prefix
|
||||
vexok_opcode_expr = "^v.*"
|
||||
vexok_expr = "\\(v1\\)"
|
||||
# All opcodes with (v) superscript supports *only* VEX prefix
|
||||
vexonly_expr = "\\(v\\)"
|
||||
|
||||
prefix_expr = "\\(Prefix\\)"
|
||||
prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ"
|
||||
prefix_num["REPNE"] = "INAT_PFX_REPNE"
|
||||
prefix_num["REP/REPE"] = "INAT_PFX_REPE"
|
||||
prefix_num["XACQUIRE"] = "INAT_PFX_REPNE"
|
||||
prefix_num["XRELEASE"] = "INAT_PFX_REPE"
|
||||
prefix_num["LOCK"] = "INAT_PFX_LOCK"
|
||||
prefix_num["SEG=CS"] = "INAT_PFX_CS"
|
||||
prefix_num["SEG=DS"] = "INAT_PFX_DS"
|
||||
prefix_num["SEG=ES"] = "INAT_PFX_ES"
|
||||
prefix_num["SEG=FS"] = "INAT_PFX_FS"
|
||||
prefix_num["SEG=GS"] = "INAT_PFX_GS"
|
||||
prefix_num["SEG=SS"] = "INAT_PFX_SS"
|
||||
prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ"
|
||||
prefix_num["VEX+1byte"] = "INAT_PFX_VEX2"
|
||||
prefix_num["VEX+2byte"] = "INAT_PFX_VEX3"
|
||||
|
||||
clear_vars()
|
||||
}
|
||||
|
||||
function semantic_error(msg) {
|
||||
print "Semantic error at " NR ": " msg > "/dev/stderr"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function debug(msg) {
|
||||
print "DEBUG: " msg
|
||||
}
|
||||
|
||||
function array_size(arr, i,c) {
|
||||
c = 0
|
||||
for (i in arr)
|
||||
c++
|
||||
return c
|
||||
}
|
||||
|
||||
/^Table:/ {
|
||||
print "/* " $0 " */"
|
||||
if (tname != "")
|
||||
semantic_error("Hit Table: before EndTable:.");
|
||||
}
|
||||
|
||||
/^Referrer:/ {
|
||||
if (NF != 1) {
|
||||
# escape opcode table
|
||||
ref = ""
|
||||
for (i = 2; i <= NF; i++)
|
||||
ref = ref $i
|
||||
eid = escape[ref]
|
||||
tname = sprintf("inat_escape_table_%d", eid)
|
||||
}
|
||||
}
|
||||
|
||||
/^AVXcode:/ {
|
||||
if (NF != 1) {
|
||||
# AVX/escape opcode table
|
||||
aid = $2
|
||||
if (gaid <= aid)
|
||||
gaid = aid + 1
|
||||
if (tname == "") # AVX only opcode table
|
||||
tname = sprintf("inat_avx_table_%d", $2)
|
||||
}
|
||||
if (aid == -1 && eid == -1) # primary opcode table
|
||||
tname = "inat_primary_table"
|
||||
}
|
||||
|
||||
/^GrpTable:/ {
|
||||
print "/* " $0 " */"
|
||||
if (!($2 in group))
|
||||
semantic_error("No group: " $2 )
|
||||
gid = group[$2]
|
||||
tname = "inat_group_table_" gid
|
||||
}
|
||||
|
||||
function print_table(tbl,name,fmt,n)
|
||||
{
|
||||
print "const insn_attr_t " name " = {"
|
||||
for (i = 0; i < n; i++) {
|
||||
id = sprintf(fmt, i)
|
||||
if (tbl[id])
|
||||
print " [" id "] = " tbl[id] ","
|
||||
}
|
||||
print "};"
|
||||
}
|
||||
|
||||
/^EndTable/ {
|
||||
if (gid != -1) {
|
||||
# print group tables
|
||||
if (array_size(table) != 0) {
|
||||
print_table(table, tname "[INAT_GROUP_TABLE_SIZE]",
|
||||
"0x%x", 8)
|
||||
gtable[gid,0] = tname
|
||||
}
|
||||
if (array_size(lptable1) != 0) {
|
||||
print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]",
|
||||
"0x%x", 8)
|
||||
gtable[gid,1] = tname "_1"
|
||||
}
|
||||
if (array_size(lptable2) != 0) {
|
||||
print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]",
|
||||
"0x%x", 8)
|
||||
gtable[gid,2] = tname "_2"
|
||||
}
|
||||
if (array_size(lptable3) != 0) {
|
||||
print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]",
|
||||
"0x%x", 8)
|
||||
gtable[gid,3] = tname "_3"
|
||||
}
|
||||
} else {
|
||||
# print primary/escaped tables
|
||||
if (array_size(table) != 0) {
|
||||
print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]",
|
||||
"0x%02x", 256)
|
||||
etable[eid,0] = tname
|
||||
if (aid >= 0)
|
||||
atable[aid,0] = tname
|
||||
}
|
||||
if (array_size(lptable1) != 0) {
|
||||
print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]",
|
||||
"0x%02x", 256)
|
||||
etable[eid,1] = tname "_1"
|
||||
if (aid >= 0)
|
||||
atable[aid,1] = tname "_1"
|
||||
}
|
||||
if (array_size(lptable2) != 0) {
|
||||
print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]",
|
||||
"0x%02x", 256)
|
||||
etable[eid,2] = tname "_2"
|
||||
if (aid >= 0)
|
||||
atable[aid,2] = tname "_2"
|
||||
}
|
||||
if (array_size(lptable3) != 0) {
|
||||
print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]",
|
||||
"0x%02x", 256)
|
||||
etable[eid,3] = tname "_3"
|
||||
if (aid >= 0)
|
||||
atable[aid,3] = tname "_3"
|
||||
}
|
||||
}
|
||||
print ""
|
||||
clear_vars()
|
||||
}
|
||||
|
||||
function add_flags(old,new) {
|
||||
if (old && new)
|
||||
return old " | " new
|
||||
else if (old)
|
||||
return old
|
||||
else
|
||||
return new
|
||||
}
|
||||
|
||||
# convert operands to flags.
|
||||
function convert_operands(count,opnd, i,j,imm,mod)
|
||||
{
|
||||
imm = null
|
||||
mod = null
|
||||
for (j = 1; j <= count; j++) {
|
||||
i = opnd[j]
|
||||
if (match(i, imm_expr) == 1) {
|
||||
if (!imm_flag[i])
|
||||
semantic_error("Unknown imm opnd: " i)
|
||||
if (imm) {
|
||||
if (i != "Ib")
|
||||
semantic_error("Second IMM error")
|
||||
imm = add_flags(imm, "INAT_SCNDIMM")
|
||||
} else
|
||||
imm = imm_flag[i]
|
||||
} else if (match(i, modrm_expr))
|
||||
mod = "INAT_MODRM"
|
||||
}
|
||||
return add_flags(imm, mod)
|
||||
}
|
||||
|
||||
/^[0-9a-f]+\:/ {
|
||||
if (NR == 1)
|
||||
next
|
||||
# get index
|
||||
idx = "0x" substr($1, 1, index($1,":") - 1)
|
||||
if (idx in table)
|
||||
semantic_error("Redefine " idx " in " tname)
|
||||
|
||||
# check if escaped opcode
|
||||
if ("escape" == $2) {
|
||||
if ($3 != "#")
|
||||
semantic_error("No escaped name")
|
||||
ref = ""
|
||||
for (i = 4; i <= NF; i++)
|
||||
ref = ref $i
|
||||
if (ref in escape)
|
||||
semantic_error("Redefine escape (" ref ")")
|
||||
escape[ref] = geid
|
||||
geid++
|
||||
table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")"
|
||||
next
|
||||
}
|
||||
|
||||
variant = null
|
||||
# converts
|
||||
i = 2
|
||||
while (i <= NF) {
|
||||
opcode = $(i++)
|
||||
delete opnds
|
||||
ext = null
|
||||
flags = null
|
||||
opnd = null
|
||||
# parse one opcode
|
||||
if (match($i, opnd_expr)) {
|
||||
opnd = $i
|
||||
count = split($(i++), opnds, ",")
|
||||
flags = convert_operands(count, opnds)
|
||||
}
|
||||
if (match($i, ext_expr))
|
||||
ext = $(i++)
|
||||
if (match($i, sep_expr))
|
||||
i++
|
||||
else if (i < NF)
|
||||
semantic_error($i " is not a separator")
|
||||
|
||||
# check if group opcode
|
||||
if (match(opcode, group_expr)) {
|
||||
if (!(opcode in group)) {
|
||||
group[opcode] = ggid
|
||||
ggid++
|
||||
}
|
||||
flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")")
|
||||
}
|
||||
# check force(or default) 64bit
|
||||
if (match(ext, force64_expr))
|
||||
flags = add_flags(flags, "INAT_FORCE64")
|
||||
|
||||
# check REX prefix
|
||||
if (match(opcode, rex_expr))
|
||||
flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)")
|
||||
|
||||
# check coprocessor escape : TODO
|
||||
if (match(opcode, fpu_expr))
|
||||
flags = add_flags(flags, "INAT_MODRM")
|
||||
|
||||
# check VEX codes
|
||||
if (match(ext, vexonly_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY")
|
||||
else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr))
|
||||
flags = add_flags(flags, "INAT_VEXOK")
|
||||
|
||||
# check prefixes
|
||||
if (match(ext, prefix_expr)) {
|
||||
if (!prefix_num[opcode])
|
||||
semantic_error("Unknown prefix: " opcode)
|
||||
flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")")
|
||||
}
|
||||
if (length(flags) == 0)
|
||||
continue
|
||||
# check if last prefix
|
||||
if (match(ext, lprefix1_expr)) {
|
||||
lptable1[idx] = add_flags(lptable1[idx],flags)
|
||||
variant = "INAT_VARIANT"
|
||||
}
|
||||
if (match(ext, lprefix2_expr)) {
|
||||
lptable2[idx] = add_flags(lptable2[idx],flags)
|
||||
variant = "INAT_VARIANT"
|
||||
}
|
||||
if (match(ext, lprefix3_expr)) {
|
||||
lptable3[idx] = add_flags(lptable3[idx],flags)
|
||||
variant = "INAT_VARIANT"
|
||||
}
|
||||
if (!match(ext, lprefix_expr)){
|
||||
table[idx] = add_flags(table[idx],flags)
|
||||
}
|
||||
}
|
||||
if (variant)
|
||||
table[idx] = add_flags(table[idx],variant)
|
||||
}
|
||||
|
||||
END {
|
||||
if (awkchecked != "")
|
||||
exit 1
|
||||
# print escape opcode map's array
|
||||
print "/* Escape opcode map array */"
|
||||
print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \
|
||||
"[INAT_LSTPFX_MAX + 1] = {"
|
||||
for (i = 0; i < geid; i++)
|
||||
for (j = 0; j < max_lprefix; j++)
|
||||
if (etable[i,j])
|
||||
print " ["i"]["j"] = "etable[i,j]","
|
||||
print "};\n"
|
||||
# print group opcode map's array
|
||||
print "/* Group opcode map array */"
|
||||
print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\
|
||||
"[INAT_LSTPFX_MAX + 1] = {"
|
||||
for (i = 0; i < ggid; i++)
|
||||
for (j = 0; j < max_lprefix; j++)
|
||||
if (gtable[i,j])
|
||||
print " ["i"]["j"] = "gtable[i,j]","
|
||||
print "};\n"
|
||||
# print AVX opcode map's array
|
||||
print "/* AVX opcode map array */"
|
||||
print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\
|
||||
"[INAT_LSTPFX_MAX + 1] = {"
|
||||
for (i = 0; i < gaid; i++)
|
||||
for (j = 0; j < max_lprefix; j++)
|
||||
if (atable[i,j])
|
||||
print " ["i"]["j"] = "atable[i,j]","
|
||||
print "};"
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* x86 instruction attribute tables
|
||||
*
|
||||
* Written by Masami Hiramatsu <mhiramat@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
#include <asm/insn.h>
|
||||
|
||||
/* Attribute tables are generated from opcode map */
|
||||
#include "inat-tables.c"
|
||||
|
||||
/* Attribute search APIs */
|
||||
insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode)
|
||||
{
|
||||
return inat_primary_table[opcode];
|
||||
}
|
||||
|
||||
int inat_get_last_prefix_id(insn_byte_t last_pfx)
|
||||
{
|
||||
insn_attr_t lpfx_attr;
|
||||
|
||||
lpfx_attr = inat_get_opcode_attribute(last_pfx);
|
||||
return inat_last_prefix_id(lpfx_attr);
|
||||
}
|
||||
|
||||
insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id,
|
||||
insn_attr_t esc_attr)
|
||||
{
|
||||
const insn_attr_t *table;
|
||||
int n;
|
||||
|
||||
n = inat_escape_id(esc_attr);
|
||||
|
||||
table = inat_escape_tables[n][0];
|
||||
if (!table)
|
||||
return 0;
|
||||
if (inat_has_variant(table[opcode]) && lpfx_id) {
|
||||
table = inat_escape_tables[n][lpfx_id];
|
||||
if (!table)
|
||||
return 0;
|
||||
}
|
||||
return table[opcode];
|
||||
}
|
||||
|
||||
insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id,
|
||||
insn_attr_t grp_attr)
|
||||
{
|
||||
const insn_attr_t *table;
|
||||
int n;
|
||||
|
||||
n = inat_group_id(grp_attr);
|
||||
|
||||
table = inat_group_tables[n][0];
|
||||
if (!table)
|
||||
return inat_group_common_attribute(grp_attr);
|
||||
if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) {
|
||||
table = inat_group_tables[n][lpfx_id];
|
||||
if (!table)
|
||||
return inat_group_common_attribute(grp_attr);
|
||||
}
|
||||
return table[X86_MODRM_REG(modrm)] |
|
||||
inat_group_common_attribute(grp_attr);
|
||||
}
|
||||
|
||||
insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m,
|
||||
insn_byte_t vex_p)
|
||||
{
|
||||
const insn_attr_t *table;
|
||||
if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX)
|
||||
return 0;
|
||||
/* At first, this checks the master table */
|
||||
table = inat_avx_tables[vex_m][0];
|
||||
if (!table)
|
||||
return 0;
|
||||
if (!inat_is_group(table[opcode]) && vex_p) {
|
||||
/* If this is not a group, get attribute directly */
|
||||
table = inat_avx_tables[vex_m][vex_p];
|
||||
if (!table)
|
||||
return 0;
|
||||
}
|
||||
return table[opcode];
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
#ifndef _ASM_X86_INAT_H
|
||||
#define _ASM_X86_INAT_H
|
||||
/*
|
||||
* x86 instruction attributes
|
||||
*
|
||||
* Written by Masami Hiramatsu <mhiramat@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
#include <asm/inat_types.h>
|
||||
|
||||
/*
|
||||
* Internal bits. Don't use bitmasks directly, because these bits are
|
||||
* unstable. You should use checking functions.
|
||||
*/
|
||||
|
||||
#define INAT_OPCODE_TABLE_SIZE 256
|
||||
#define INAT_GROUP_TABLE_SIZE 8
|
||||
|
||||
/* Legacy last prefixes */
|
||||
#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */
|
||||
#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */
|
||||
#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */
|
||||
/* Other Legacy prefixes */
|
||||
#define INAT_PFX_LOCK 4 /* 0xF0 */
|
||||
#define INAT_PFX_CS 5 /* 0x2E */
|
||||
#define INAT_PFX_DS 6 /* 0x3E */
|
||||
#define INAT_PFX_ES 7 /* 0x26 */
|
||||
#define INAT_PFX_FS 8 /* 0x64 */
|
||||
#define INAT_PFX_GS 9 /* 0x65 */
|
||||
#define INAT_PFX_SS 10 /* 0x36 */
|
||||
#define INAT_PFX_ADDRSZ 11 /* 0x67 */
|
||||
/* x86-64 REX prefix */
|
||||
#define INAT_PFX_REX 12 /* 0x4X */
|
||||
/* AVX VEX prefixes */
|
||||
#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */
|
||||
#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */
|
||||
|
||||
#define INAT_LSTPFX_MAX 3
|
||||
#define INAT_LGCPFX_MAX 11
|
||||
|
||||
/* Immediate size */
|
||||
#define INAT_IMM_BYTE 1
|
||||
#define INAT_IMM_WORD 2
|
||||
#define INAT_IMM_DWORD 3
|
||||
#define INAT_IMM_QWORD 4
|
||||
#define INAT_IMM_PTR 5
|
||||
#define INAT_IMM_VWORD32 6
|
||||
#define INAT_IMM_VWORD 7
|
||||
|
||||
/* Legacy prefix */
|
||||
#define INAT_PFX_OFFS 0
|
||||
#define INAT_PFX_BITS 4
|
||||
#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1)
|
||||
#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS)
|
||||
/* Escape opcodes */
|
||||
#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS)
|
||||
#define INAT_ESC_BITS 2
|
||||
#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1)
|
||||
#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS)
|
||||
/* Group opcodes (1-16) */
|
||||
#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS)
|
||||
#define INAT_GRP_BITS 5
|
||||
#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1)
|
||||
#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS)
|
||||
/* Immediates */
|
||||
#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS)
|
||||
#define INAT_IMM_BITS 3
|
||||
#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS)
|
||||
/* Flags */
|
||||
#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS)
|
||||
#define INAT_MODRM (1 << (INAT_FLAG_OFFS))
|
||||
#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1))
|
||||
#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2))
|
||||
#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3))
|
||||
#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4))
|
||||
#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5))
|
||||
#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6))
|
||||
/* Attribute making macros for attribute tables */
|
||||
#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS)
|
||||
#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS)
|
||||
#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM)
|
||||
#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS)
|
||||
|
||||
/* Attribute search APIs */
|
||||
extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode);
|
||||
extern int inat_get_last_prefix_id(insn_byte_t last_pfx);
|
||||
extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode,
|
||||
int lpfx_id,
|
||||
insn_attr_t esc_attr);
|
||||
extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm,
|
||||
int lpfx_id,
|
||||
insn_attr_t esc_attr);
|
||||
extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode,
|
||||
insn_byte_t vex_m,
|
||||
insn_byte_t vex_pp);
|
||||
|
||||
/* Attribute checking functions */
|
||||
static inline int inat_is_legacy_prefix(insn_attr_t attr)
|
||||
{
|
||||
attr &= INAT_PFX_MASK;
|
||||
return attr && attr <= INAT_LGCPFX_MAX;
|
||||
}
|
||||
|
||||
static inline int inat_is_address_size_prefix(insn_attr_t attr)
|
||||
{
|
||||
return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ;
|
||||
}
|
||||
|
||||
static inline int inat_is_operand_size_prefix(insn_attr_t attr)
|
||||
{
|
||||
return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ;
|
||||
}
|
||||
|
||||
static inline int inat_is_rex_prefix(insn_attr_t attr)
|
||||
{
|
||||
return (attr & INAT_PFX_MASK) == INAT_PFX_REX;
|
||||
}
|
||||
|
||||
static inline int inat_last_prefix_id(insn_attr_t attr)
|
||||
{
|
||||
if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX)
|
||||
return 0;
|
||||
else
|
||||
return attr & INAT_PFX_MASK;
|
||||
}
|
||||
|
||||
static inline int inat_is_vex_prefix(insn_attr_t attr)
|
||||
{
|
||||
attr &= INAT_PFX_MASK;
|
||||
return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3;
|
||||
}
|
||||
|
||||
static inline int inat_is_vex3_prefix(insn_attr_t attr)
|
||||
{
|
||||
return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3;
|
||||
}
|
||||
|
||||
static inline int inat_is_escape(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_ESC_MASK;
|
||||
}
|
||||
|
||||
static inline int inat_escape_id(insn_attr_t attr)
|
||||
{
|
||||
return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS;
|
||||
}
|
||||
|
||||
static inline int inat_is_group(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_GRP_MASK;
|
||||
}
|
||||
|
||||
static inline int inat_group_id(insn_attr_t attr)
|
||||
{
|
||||
return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS;
|
||||
}
|
||||
|
||||
static inline int inat_group_common_attribute(insn_attr_t attr)
|
||||
{
|
||||
return attr & ~INAT_GRP_MASK;
|
||||
}
|
||||
|
||||
static inline int inat_has_immediate(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_IMM_MASK;
|
||||
}
|
||||
|
||||
static inline int inat_immediate_size(insn_attr_t attr)
|
||||
{
|
||||
return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS;
|
||||
}
|
||||
|
||||
static inline int inat_has_modrm(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_MODRM;
|
||||
}
|
||||
|
||||
static inline int inat_is_force64(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_FORCE64;
|
||||
}
|
||||
|
||||
static inline int inat_has_second_immediate(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_SCNDIMM;
|
||||
}
|
||||
|
||||
static inline int inat_has_moffset(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_MOFFSET;
|
||||
}
|
||||
|
||||
static inline int inat_has_variant(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_VARIANT;
|
||||
}
|
||||
|
||||
static inline int inat_accept_vex(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_VEXOK;
|
||||
}
|
||||
|
||||
static inline int inat_must_vex(insn_attr_t attr)
|
||||
{
|
||||
return attr & INAT_VEXONLY;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,594 @@
|
|||
/*
|
||||
* x86 instruction analysis
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2002, 2004, 2009
|
||||
*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/string.h>
|
||||
#else
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <asm/inat.h>
|
||||
#include <asm/insn.h>
|
||||
|
||||
/* Verify next sizeof(t) bytes can be on the same instruction */
|
||||
#define validate_next(t, insn, n) \
|
||||
((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
|
||||
|
||||
#define __get_next(t, insn) \
|
||||
({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; })
|
||||
|
||||
#define __peek_nbyte_next(t, insn, n) \
|
||||
({ t r = *(t*)((insn)->next_byte + n); r; })
|
||||
|
||||
#define get_next(t, insn) \
|
||||
({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); })
|
||||
|
||||
#define peek_nbyte_next(t, insn, n) \
|
||||
({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); })
|
||||
|
||||
#define peek_next(t, insn) peek_nbyte_next(t, insn, 0)
|
||||
|
||||
/**
|
||||
* insn_init() - initialize struct insn
|
||||
* @insn: &struct insn to be initialized
|
||||
* @kaddr: address (in kernel memory) of instruction (or copy thereof)
|
||||
* @x86_64: !0 for 64-bit kernel or 64-bit app
|
||||
*/
|
||||
void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
|
||||
{
|
||||
/*
|
||||
* Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid
|
||||
* even if the input buffer is long enough to hold them.
|
||||
*/
|
||||
if (buf_len > MAX_INSN_SIZE)
|
||||
buf_len = MAX_INSN_SIZE;
|
||||
|
||||
memset(insn, 0, sizeof(*insn));
|
||||
insn->kaddr = kaddr;
|
||||
insn->end_kaddr = kaddr + buf_len;
|
||||
insn->next_byte = kaddr;
|
||||
insn->x86_64 = x86_64 ? 1 : 0;
|
||||
insn->opnd_bytes = 4;
|
||||
if (x86_64)
|
||||
insn->addr_bytes = 8;
|
||||
else
|
||||
insn->addr_bytes = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* insn_get_prefixes - scan x86 instruction prefix bytes
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* Populates the @insn->prefixes bitmap, and updates @insn->next_byte
|
||||
* to point to the (first) opcode. No effect if @insn->prefixes.got
|
||||
* is already set.
|
||||
*/
|
||||
void insn_get_prefixes(struct insn *insn)
|
||||
{
|
||||
struct insn_field *prefixes = &insn->prefixes;
|
||||
insn_attr_t attr;
|
||||
insn_byte_t b, lb;
|
||||
int i, nb;
|
||||
|
||||
if (prefixes->got)
|
||||
return;
|
||||
|
||||
nb = 0;
|
||||
lb = 0;
|
||||
b = peek_next(insn_byte_t, insn);
|
||||
attr = inat_get_opcode_attribute(b);
|
||||
while (inat_is_legacy_prefix(attr)) {
|
||||
/* Skip if same prefix */
|
||||
for (i = 0; i < nb; i++)
|
||||
if (prefixes->bytes[i] == b)
|
||||
goto found;
|
||||
if (nb == 4)
|
||||
/* Invalid instruction */
|
||||
break;
|
||||
prefixes->bytes[nb++] = b;
|
||||
if (inat_is_address_size_prefix(attr)) {
|
||||
/* address size switches 2/4 or 4/8 */
|
||||
if (insn->x86_64)
|
||||
insn->addr_bytes ^= 12;
|
||||
else
|
||||
insn->addr_bytes ^= 6;
|
||||
} else if (inat_is_operand_size_prefix(attr)) {
|
||||
/* oprand size switches 2/4 */
|
||||
insn->opnd_bytes ^= 6;
|
||||
}
|
||||
found:
|
||||
prefixes->nbytes++;
|
||||
insn->next_byte++;
|
||||
lb = b;
|
||||
b = peek_next(insn_byte_t, insn);
|
||||
attr = inat_get_opcode_attribute(b);
|
||||
}
|
||||
/* Set the last prefix */
|
||||
if (lb && lb != insn->prefixes.bytes[3]) {
|
||||
if (unlikely(insn->prefixes.bytes[3])) {
|
||||
/* Swap the last prefix */
|
||||
b = insn->prefixes.bytes[3];
|
||||
for (i = 0; i < nb; i++)
|
||||
if (prefixes->bytes[i] == lb)
|
||||
prefixes->bytes[i] = b;
|
||||
}
|
||||
insn->prefixes.bytes[3] = lb;
|
||||
}
|
||||
|
||||
/* Decode REX prefix */
|
||||
if (insn->x86_64) {
|
||||
b = peek_next(insn_byte_t, insn);
|
||||
attr = inat_get_opcode_attribute(b);
|
||||
if (inat_is_rex_prefix(attr)) {
|
||||
insn->rex_prefix.value = b;
|
||||
insn->rex_prefix.nbytes = 1;
|
||||
insn->next_byte++;
|
||||
if (X86_REX_W(b))
|
||||
/* REX.W overrides opnd_size */
|
||||
insn->opnd_bytes = 8;
|
||||
}
|
||||
}
|
||||
insn->rex_prefix.got = 1;
|
||||
|
||||
/* Decode VEX prefix */
|
||||
b = peek_next(insn_byte_t, insn);
|
||||
attr = inat_get_opcode_attribute(b);
|
||||
if (inat_is_vex_prefix(attr)) {
|
||||
insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1);
|
||||
if (!insn->x86_64) {
|
||||
/*
|
||||
* In 32-bits mode, if the [7:6] bits (mod bits of
|
||||
* ModRM) on the second byte are not 11b, it is
|
||||
* LDS or LES.
|
||||
*/
|
||||
if (X86_MODRM_MOD(b2) != 3)
|
||||
goto vex_end;
|
||||
}
|
||||
insn->vex_prefix.bytes[0] = b;
|
||||
insn->vex_prefix.bytes[1] = b2;
|
||||
if (inat_is_vex3_prefix(attr)) {
|
||||
b2 = peek_nbyte_next(insn_byte_t, insn, 2);
|
||||
insn->vex_prefix.bytes[2] = b2;
|
||||
insn->vex_prefix.nbytes = 3;
|
||||
insn->next_byte += 3;
|
||||
if (insn->x86_64 && X86_VEX_W(b2))
|
||||
/* VEX.W overrides opnd_size */
|
||||
insn->opnd_bytes = 8;
|
||||
} else {
|
||||
/*
|
||||
* For VEX2, fake VEX3-like byte#2.
|
||||
* Makes it easier to decode vex.W, vex.vvvv,
|
||||
* vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
|
||||
*/
|
||||
insn->vex_prefix.bytes[2] = b2 & 0x7f;
|
||||
insn->vex_prefix.nbytes = 2;
|
||||
insn->next_byte += 2;
|
||||
}
|
||||
}
|
||||
vex_end:
|
||||
insn->vex_prefix.got = 1;
|
||||
|
||||
prefixes->got = 1;
|
||||
|
||||
err_out:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* insn_get_opcode - collect opcode(s)
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* Populates @insn->opcode, updates @insn->next_byte to point past the
|
||||
* opcode byte(s), and set @insn->attr (except for groups).
|
||||
* If necessary, first collects any preceding (prefix) bytes.
|
||||
* Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got
|
||||
* is already 1.
|
||||
*/
|
||||
void insn_get_opcode(struct insn *insn)
|
||||
{
|
||||
struct insn_field *opcode = &insn->opcode;
|
||||
insn_byte_t op;
|
||||
int pfx_id;
|
||||
if (opcode->got)
|
||||
return;
|
||||
if (!insn->prefixes.got)
|
||||
insn_get_prefixes(insn);
|
||||
|
||||
/* Get first opcode */
|
||||
op = get_next(insn_byte_t, insn);
|
||||
opcode->bytes[0] = op;
|
||||
opcode->nbytes = 1;
|
||||
|
||||
/* Check if there is VEX prefix or not */
|
||||
if (insn_is_avx(insn)) {
|
||||
insn_byte_t m, p;
|
||||
m = insn_vex_m_bits(insn);
|
||||
p = insn_vex_p_bits(insn);
|
||||
insn->attr = inat_get_avx_attribute(op, m, p);
|
||||
if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr))
|
||||
insn->attr = 0; /* This instruction is bad */
|
||||
goto end; /* VEX has only 1 byte for opcode */
|
||||
}
|
||||
|
||||
insn->attr = inat_get_opcode_attribute(op);
|
||||
while (inat_is_escape(insn->attr)) {
|
||||
/* Get escaped opcode */
|
||||
op = get_next(insn_byte_t, insn);
|
||||
opcode->bytes[opcode->nbytes++] = op;
|
||||
pfx_id = insn_last_prefix_id(insn);
|
||||
insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr);
|
||||
}
|
||||
if (inat_must_vex(insn->attr))
|
||||
insn->attr = 0; /* This instruction is bad */
|
||||
end:
|
||||
opcode->got = 1;
|
||||
|
||||
err_out:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* insn_get_modrm - collect ModRM byte, if any
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* Populates @insn->modrm and updates @insn->next_byte to point past the
|
||||
* ModRM byte, if any. If necessary, first collects the preceding bytes
|
||||
* (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1.
|
||||
*/
|
||||
void insn_get_modrm(struct insn *insn)
|
||||
{
|
||||
struct insn_field *modrm = &insn->modrm;
|
||||
insn_byte_t pfx_id, mod;
|
||||
if (modrm->got)
|
||||
return;
|
||||
if (!insn->opcode.got)
|
||||
insn_get_opcode(insn);
|
||||
|
||||
if (inat_has_modrm(insn->attr)) {
|
||||
mod = get_next(insn_byte_t, insn);
|
||||
modrm->value = mod;
|
||||
modrm->nbytes = 1;
|
||||
if (inat_is_group(insn->attr)) {
|
||||
pfx_id = insn_last_prefix_id(insn);
|
||||
insn->attr = inat_get_group_attribute(mod, pfx_id,
|
||||
insn->attr);
|
||||
if (insn_is_avx(insn) && !inat_accept_vex(insn->attr))
|
||||
insn->attr = 0; /* This is bad */
|
||||
}
|
||||
}
|
||||
|
||||
if (insn->x86_64 && inat_is_force64(insn->attr))
|
||||
insn->opnd_bytes = 8;
|
||||
modrm->got = 1;
|
||||
|
||||
err_out:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* insn_rip_relative() - Does instruction use RIP-relative addressing mode?
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* If necessary, first collects the instruction up to and including the
|
||||
* ModRM byte. No effect if @insn->x86_64 is 0.
|
||||
*/
|
||||
int insn_rip_relative(struct insn *insn)
|
||||
{
|
||||
struct insn_field *modrm = &insn->modrm;
|
||||
|
||||
if (!insn->x86_64)
|
||||
return 0;
|
||||
if (!modrm->got)
|
||||
insn_get_modrm(insn);
|
||||
/*
|
||||
* For rip-relative instructions, the mod field (top 2 bits)
|
||||
* is zero and the r/m field (bottom 3 bits) is 0x5.
|
||||
*/
|
||||
return (modrm->nbytes && (modrm->value & 0xc7) == 0x5);
|
||||
}
|
||||
|
||||
/**
|
||||
* insn_get_sib() - Get the SIB byte of instruction
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* If necessary, first collects the instruction up to and including the
|
||||
* ModRM byte.
|
||||
*/
|
||||
void insn_get_sib(struct insn *insn)
|
||||
{
|
||||
insn_byte_t modrm;
|
||||
|
||||
if (insn->sib.got)
|
||||
return;
|
||||
if (!insn->modrm.got)
|
||||
insn_get_modrm(insn);
|
||||
if (insn->modrm.nbytes) {
|
||||
modrm = (insn_byte_t)insn->modrm.value;
|
||||
if (insn->addr_bytes != 2 &&
|
||||
X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) {
|
||||
insn->sib.value = get_next(insn_byte_t, insn);
|
||||
insn->sib.nbytes = 1;
|
||||
}
|
||||
}
|
||||
insn->sib.got = 1;
|
||||
|
||||
err_out:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* insn_get_displacement() - Get the displacement of instruction
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* If necessary, first collects the instruction up to and including the
|
||||
* SIB byte.
|
||||
* Displacement value is sign-expanded.
|
||||
*/
|
||||
void insn_get_displacement(struct insn *insn)
|
||||
{
|
||||
insn_byte_t mod, rm, base;
|
||||
|
||||
if (insn->displacement.got)
|
||||
return;
|
||||
if (!insn->sib.got)
|
||||
insn_get_sib(insn);
|
||||
if (insn->modrm.nbytes) {
|
||||
/*
|
||||
* Interpreting the modrm byte:
|
||||
* mod = 00 - no displacement fields (exceptions below)
|
||||
* mod = 01 - 1-byte displacement field
|
||||
* mod = 10 - displacement field is 4 bytes, or 2 bytes if
|
||||
* address size = 2 (0x67 prefix in 32-bit mode)
|
||||
* mod = 11 - no memory operand
|
||||
*
|
||||
* If address size = 2...
|
||||
* mod = 00, r/m = 110 - displacement field is 2 bytes
|
||||
*
|
||||
* If address size != 2...
|
||||
* mod != 11, r/m = 100 - SIB byte exists
|
||||
* mod = 00, SIB base = 101 - displacement field is 4 bytes
|
||||
* mod = 00, r/m = 101 - rip-relative addressing, displacement
|
||||
* field is 4 bytes
|
||||
*/
|
||||
mod = X86_MODRM_MOD(insn->modrm.value);
|
||||
rm = X86_MODRM_RM(insn->modrm.value);
|
||||
base = X86_SIB_BASE(insn->sib.value);
|
||||
if (mod == 3)
|
||||
goto out;
|
||||
if (mod == 1) {
|
||||
insn->displacement.value = get_next(char, insn);
|
||||
insn->displacement.nbytes = 1;
|
||||
} else if (insn->addr_bytes == 2) {
|
||||
if ((mod == 0 && rm == 6) || mod == 2) {
|
||||
insn->displacement.value =
|
||||
get_next(short, insn);
|
||||
insn->displacement.nbytes = 2;
|
||||
}
|
||||
} else {
|
||||
if ((mod == 0 && rm == 5) || mod == 2 ||
|
||||
(mod == 0 && base == 5)) {
|
||||
insn->displacement.value = get_next(int, insn);
|
||||
insn->displacement.nbytes = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
insn->displacement.got = 1;
|
||||
|
||||
err_out:
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decode moffset16/32/64. Return 0 if failed */
|
||||
static int __get_moffset(struct insn *insn)
|
||||
{
|
||||
switch (insn->addr_bytes) {
|
||||
case 2:
|
||||
insn->moffset1.value = get_next(short, insn);
|
||||
insn->moffset1.nbytes = 2;
|
||||
break;
|
||||
case 4:
|
||||
insn->moffset1.value = get_next(int, insn);
|
||||
insn->moffset1.nbytes = 4;
|
||||
break;
|
||||
case 8:
|
||||
insn->moffset1.value = get_next(int, insn);
|
||||
insn->moffset1.nbytes = 4;
|
||||
insn->moffset2.value = get_next(int, insn);
|
||||
insn->moffset2.nbytes = 4;
|
||||
break;
|
||||
default: /* opnd_bytes must be modified manually */
|
||||
goto err_out;
|
||||
}
|
||||
insn->moffset1.got = insn->moffset2.got = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
err_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decode imm v32(Iz). Return 0 if failed */
|
||||
static int __get_immv32(struct insn *insn)
|
||||
{
|
||||
switch (insn->opnd_bytes) {
|
||||
case 2:
|
||||
insn->immediate.value = get_next(short, insn);
|
||||
insn->immediate.nbytes = 2;
|
||||
break;
|
||||
case 4:
|
||||
case 8:
|
||||
insn->immediate.value = get_next(int, insn);
|
||||
insn->immediate.nbytes = 4;
|
||||
break;
|
||||
default: /* opnd_bytes must be modified manually */
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
err_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decode imm v64(Iv/Ov), Return 0 if failed */
|
||||
static int __get_immv(struct insn *insn)
|
||||
{
|
||||
switch (insn->opnd_bytes) {
|
||||
case 2:
|
||||
insn->immediate1.value = get_next(short, insn);
|
||||
insn->immediate1.nbytes = 2;
|
||||
break;
|
||||
case 4:
|
||||
insn->immediate1.value = get_next(int, insn);
|
||||
insn->immediate1.nbytes = 4;
|
||||
break;
|
||||
case 8:
|
||||
insn->immediate1.value = get_next(int, insn);
|
||||
insn->immediate1.nbytes = 4;
|
||||
insn->immediate2.value = get_next(int, insn);
|
||||
insn->immediate2.nbytes = 4;
|
||||
break;
|
||||
default: /* opnd_bytes must be modified manually */
|
||||
goto err_out;
|
||||
}
|
||||
insn->immediate1.got = insn->immediate2.got = 1;
|
||||
|
||||
return 1;
|
||||
err_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Decode ptr16:16/32(Ap) */
|
||||
static int __get_immptr(struct insn *insn)
|
||||
{
|
||||
switch (insn->opnd_bytes) {
|
||||
case 2:
|
||||
insn->immediate1.value = get_next(short, insn);
|
||||
insn->immediate1.nbytes = 2;
|
||||
break;
|
||||
case 4:
|
||||
insn->immediate1.value = get_next(int, insn);
|
||||
insn->immediate1.nbytes = 4;
|
||||
break;
|
||||
case 8:
|
||||
/* ptr16:64 is not exist (no segment) */
|
||||
return 0;
|
||||
default: /* opnd_bytes must be modified manually */
|
||||
goto err_out;
|
||||
}
|
||||
insn->immediate2.value = get_next(unsigned short, insn);
|
||||
insn->immediate2.nbytes = 2;
|
||||
insn->immediate1.got = insn->immediate2.got = 1;
|
||||
|
||||
return 1;
|
||||
err_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* insn_get_immediate() - Get the immediates of instruction
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* If necessary, first collects the instruction up to and including the
|
||||
* displacement bytes.
|
||||
* Basically, most of immediates are sign-expanded. Unsigned-value can be
|
||||
* get by bit masking with ((1 << (nbytes * 8)) - 1)
|
||||
*/
|
||||
void insn_get_immediate(struct insn *insn)
|
||||
{
|
||||
if (insn->immediate.got)
|
||||
return;
|
||||
if (!insn->displacement.got)
|
||||
insn_get_displacement(insn);
|
||||
|
||||
if (inat_has_moffset(insn->attr)) {
|
||||
if (!__get_moffset(insn))
|
||||
goto err_out;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!inat_has_immediate(insn->attr))
|
||||
/* no immediates */
|
||||
goto done;
|
||||
|
||||
switch (inat_immediate_size(insn->attr)) {
|
||||
case INAT_IMM_BYTE:
|
||||
insn->immediate.value = get_next(char, insn);
|
||||
insn->immediate.nbytes = 1;
|
||||
break;
|
||||
case INAT_IMM_WORD:
|
||||
insn->immediate.value = get_next(short, insn);
|
||||
insn->immediate.nbytes = 2;
|
||||
break;
|
||||
case INAT_IMM_DWORD:
|
||||
insn->immediate.value = get_next(int, insn);
|
||||
insn->immediate.nbytes = 4;
|
||||
break;
|
||||
case INAT_IMM_QWORD:
|
||||
insn->immediate1.value = get_next(int, insn);
|
||||
insn->immediate1.nbytes = 4;
|
||||
insn->immediate2.value = get_next(int, insn);
|
||||
insn->immediate2.nbytes = 4;
|
||||
break;
|
||||
case INAT_IMM_PTR:
|
||||
if (!__get_immptr(insn))
|
||||
goto err_out;
|
||||
break;
|
||||
case INAT_IMM_VWORD32:
|
||||
if (!__get_immv32(insn))
|
||||
goto err_out;
|
||||
break;
|
||||
case INAT_IMM_VWORD:
|
||||
if (!__get_immv(insn))
|
||||
goto err_out;
|
||||
break;
|
||||
default:
|
||||
/* Here, insn must have an immediate, but failed */
|
||||
goto err_out;
|
||||
}
|
||||
if (inat_has_second_immediate(insn->attr)) {
|
||||
insn->immediate2.value = get_next(char, insn);
|
||||
insn->immediate2.nbytes = 1;
|
||||
}
|
||||
done:
|
||||
insn->immediate.got = 1;
|
||||
|
||||
err_out:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* insn_get_length() - Get the length of instruction
|
||||
* @insn: &struct insn containing instruction
|
||||
*
|
||||
* If necessary, first collects the instruction up to and including the
|
||||
* immediates bytes.
|
||||
*/
|
||||
void insn_get_length(struct insn *insn)
|
||||
{
|
||||
if (insn->length)
|
||||
return;
|
||||
if (!insn->immediate.got)
|
||||
insn_get_immediate(insn);
|
||||
insn->length = (unsigned char)((unsigned long)insn->next_byte
|
||||
- (unsigned long)insn->kaddr);
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
#ifndef _ASM_X86_INSN_H
|
||||
#define _ASM_X86_INSN_H
|
||||
/*
|
||||
* x86 instruction analysis
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2009
|
||||
*/
|
||||
|
||||
/* insn_attr_t is defined in inat.h */
|
||||
#include <asm/inat.h>
|
||||
|
||||
struct insn_field {
|
||||
union {
|
||||
insn_value_t value;
|
||||
insn_byte_t bytes[4];
|
||||
};
|
||||
/* !0 if we've run insn_get_xxx() for this field */
|
||||
unsigned char got;
|
||||
unsigned char nbytes;
|
||||
};
|
||||
|
||||
struct insn {
|
||||
struct insn_field prefixes; /*
|
||||
* Prefixes
|
||||
* prefixes.bytes[3]: last prefix
|
||||
*/
|
||||
struct insn_field rex_prefix; /* REX prefix */
|
||||
struct insn_field vex_prefix; /* VEX prefix */
|
||||
struct insn_field opcode; /*
|
||||
* opcode.bytes[0]: opcode1
|
||||
* opcode.bytes[1]: opcode2
|
||||
* opcode.bytes[2]: opcode3
|
||||
*/
|
||||
struct insn_field modrm;
|
||||
struct insn_field sib;
|
||||
struct insn_field displacement;
|
||||
union {
|
||||
struct insn_field immediate;
|
||||
struct insn_field moffset1; /* for 64bit MOV */
|
||||
struct insn_field immediate1; /* for 64bit imm or off16/32 */
|
||||
};
|
||||
union {
|
||||
struct insn_field moffset2; /* for 64bit MOV */
|
||||
struct insn_field immediate2; /* for 64bit imm or seg16 */
|
||||
};
|
||||
|
||||
insn_attr_t attr;
|
||||
unsigned char opnd_bytes;
|
||||
unsigned char addr_bytes;
|
||||
unsigned char length;
|
||||
unsigned char x86_64;
|
||||
|
||||
const insn_byte_t *kaddr; /* kernel address of insn to analyze */
|
||||
const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */
|
||||
const insn_byte_t *next_byte;
|
||||
};
|
||||
|
||||
#define MAX_INSN_SIZE 15
|
||||
|
||||
#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6)
|
||||
#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3)
|
||||
#define X86_MODRM_RM(modrm) ((modrm) & 0x07)
|
||||
|
||||
#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6)
|
||||
#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3)
|
||||
#define X86_SIB_BASE(sib) ((sib) & 0x07)
|
||||
|
||||
#define X86_REX_W(rex) ((rex) & 8)
|
||||
#define X86_REX_R(rex) ((rex) & 4)
|
||||
#define X86_REX_X(rex) ((rex) & 2)
|
||||
#define X86_REX_B(rex) ((rex) & 1)
|
||||
|
||||
/* VEX bit flags */
|
||||
#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */
|
||||
#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */
|
||||
#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */
|
||||
#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */
|
||||
#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */
|
||||
/* VEX bit fields */
|
||||
#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */
|
||||
#define X86_VEX2_M 1 /* VEX2.M always 1 */
|
||||
#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */
|
||||
#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */
|
||||
#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */
|
||||
|
||||
extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64);
|
||||
extern void insn_get_prefixes(struct insn *insn);
|
||||
extern void insn_get_opcode(struct insn *insn);
|
||||
extern void insn_get_modrm(struct insn *insn);
|
||||
extern void insn_get_sib(struct insn *insn);
|
||||
extern void insn_get_displacement(struct insn *insn);
|
||||
extern void insn_get_immediate(struct insn *insn);
|
||||
extern void insn_get_length(struct insn *insn);
|
||||
|
||||
/* Attribute will be determined after getting ModRM (for opcode groups) */
|
||||
static inline void insn_get_attribute(struct insn *insn)
|
||||
{
|
||||
insn_get_modrm(insn);
|
||||
}
|
||||
|
||||
/* Instruction uses RIP-relative addressing */
|
||||
extern int insn_rip_relative(struct insn *insn);
|
||||
|
||||
/* Init insn for kernel text */
|
||||
static inline void kernel_insn_init(struct insn *insn,
|
||||
const void *kaddr, int buf_len)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
insn_init(insn, kaddr, buf_len, 1);
|
||||
#else /* CONFIG_X86_32 */
|
||||
insn_init(insn, kaddr, buf_len, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int insn_is_avx(struct insn *insn)
|
||||
{
|
||||
if (!insn->prefixes.got)
|
||||
insn_get_prefixes(insn);
|
||||
return (insn->vex_prefix.value != 0);
|
||||
}
|
||||
|
||||
/* Ensure this instruction is decoded completely */
|
||||
static inline int insn_complete(struct insn *insn)
|
||||
{
|
||||
return insn->opcode.got && insn->modrm.got && insn->sib.got &&
|
||||
insn->displacement.got && insn->immediate.got;
|
||||
}
|
||||
|
||||
static inline insn_byte_t insn_vex_m_bits(struct insn *insn)
|
||||
{
|
||||
if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */
|
||||
return X86_VEX2_M;
|
||||
else
|
||||
return X86_VEX3_M(insn->vex_prefix.bytes[1]);
|
||||
}
|
||||
|
||||
static inline insn_byte_t insn_vex_p_bits(struct insn *insn)
|
||||
{
|
||||
if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */
|
||||
return X86_VEX_P(insn->vex_prefix.bytes[1]);
|
||||
else
|
||||
return X86_VEX_P(insn->vex_prefix.bytes[2]);
|
||||
}
|
||||
|
||||
/* Get the last prefix id from last prefix or VEX prefix */
|
||||
static inline int insn_last_prefix_id(struct insn *insn)
|
||||
{
|
||||
if (insn_is_avx(insn))
|
||||
return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */
|
||||
|
||||
if (insn->prefixes.bytes[3])
|
||||
return inat_get_last_prefix_id(insn->prefixes.bytes[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Offset of each field from kaddr */
|
||||
static inline int insn_offset_rex_prefix(struct insn *insn)
|
||||
{
|
||||
return insn->prefixes.nbytes;
|
||||
}
|
||||
static inline int insn_offset_vex_prefix(struct insn *insn)
|
||||
{
|
||||
return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes;
|
||||
}
|
||||
static inline int insn_offset_opcode(struct insn *insn)
|
||||
{
|
||||
return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes;
|
||||
}
|
||||
static inline int insn_offset_modrm(struct insn *insn)
|
||||
{
|
||||
return insn_offset_opcode(insn) + insn->opcode.nbytes;
|
||||
}
|
||||
static inline int insn_offset_sib(struct insn *insn)
|
||||
{
|
||||
return insn_offset_modrm(insn) + insn->modrm.nbytes;
|
||||
}
|
||||
static inline int insn_offset_displacement(struct insn *insn)
|
||||
{
|
||||
return insn_offset_sib(insn) + insn->sib.nbytes;
|
||||
}
|
||||
static inline int insn_offset_immediate(struct insn *insn)
|
||||
{
|
||||
return insn_offset_displacement(insn) + insn->displacement.nbytes;
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_INSN_H */
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* intel_pt_insn_decoder.c: Intel Processor Trace support
|
||||
* Copyright (c) 2013-2014, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
|
||||
#include "event.h"
|
||||
|
||||
#include <asm/insn.h>
|
||||
|
||||
#include "inat.c"
|
||||
#include "insn.c"
|
||||
|
||||
#include "intel-pt-insn-decoder.h"
|
||||
|
||||
/* Based on branch_type() from perf_event_intel_lbr.c */
|
||||
static void intel_pt_insn_decoder(struct insn *insn,
|
||||
struct intel_pt_insn *intel_pt_insn)
|
||||
{
|
||||
enum intel_pt_insn_op op = INTEL_PT_OP_OTHER;
|
||||
enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH;
|
||||
int ext;
|
||||
|
||||
if (insn_is_avx(insn)) {
|
||||
intel_pt_insn->op = INTEL_PT_OP_OTHER;
|
||||
intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;
|
||||
intel_pt_insn->length = insn->length;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (insn->opcode.bytes[0]) {
|
||||
case 0xf:
|
||||
switch (insn->opcode.bytes[1]) {
|
||||
case 0x05: /* syscall */
|
||||
case 0x34: /* sysenter */
|
||||
op = INTEL_PT_OP_SYSCALL;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 0x07: /* sysret */
|
||||
case 0x35: /* sysexit */
|
||||
op = INTEL_PT_OP_SYSRET;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 0x80 ... 0x8f: /* jcc */
|
||||
op = INTEL_PT_OP_JCC;
|
||||
branch = INTEL_PT_BR_CONDITIONAL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x70 ... 0x7f: /* jcc */
|
||||
op = INTEL_PT_OP_JCC;
|
||||
branch = INTEL_PT_BR_CONDITIONAL;
|
||||
break;
|
||||
case 0xc2: /* near ret */
|
||||
case 0xc3: /* near ret */
|
||||
case 0xca: /* far ret */
|
||||
case 0xcb: /* far ret */
|
||||
op = INTEL_PT_OP_RET;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 0xcf: /* iret */
|
||||
op = INTEL_PT_OP_IRET;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 0xcc ... 0xce: /* int */
|
||||
op = INTEL_PT_OP_INT;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 0xe8: /* call near rel */
|
||||
op = INTEL_PT_OP_CALL;
|
||||
branch = INTEL_PT_BR_UNCONDITIONAL;
|
||||
break;
|
||||
case 0x9a: /* call far absolute */
|
||||
op = INTEL_PT_OP_CALL;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 0xe0 ... 0xe2: /* loop */
|
||||
op = INTEL_PT_OP_LOOP;
|
||||
branch = INTEL_PT_BR_CONDITIONAL;
|
||||
break;
|
||||
case 0xe3: /* jcc */
|
||||
op = INTEL_PT_OP_JCC;
|
||||
branch = INTEL_PT_BR_CONDITIONAL;
|
||||
break;
|
||||
case 0xe9: /* jmp */
|
||||
case 0xeb: /* jmp */
|
||||
op = INTEL_PT_OP_JMP;
|
||||
branch = INTEL_PT_BR_UNCONDITIONAL;
|
||||
break;
|
||||
case 0xea: /* far jmp */
|
||||
op = INTEL_PT_OP_JMP;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 0xff: /* call near absolute, call far absolute ind */
|
||||
ext = (insn->modrm.bytes[0] >> 3) & 0x7;
|
||||
switch (ext) {
|
||||
case 2: /* near ind call */
|
||||
case 3: /* far ind call */
|
||||
op = INTEL_PT_OP_CALL;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
op = INTEL_PT_OP_JMP;
|
||||
branch = INTEL_PT_BR_INDIRECT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
intel_pt_insn->op = op;
|
||||
intel_pt_insn->branch = branch;
|
||||
intel_pt_insn->length = insn->length;
|
||||
|
||||
if (branch == INTEL_PT_BR_CONDITIONAL ||
|
||||
branch == INTEL_PT_BR_UNCONDITIONAL) {
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
switch (insn->immediate.nbytes) {
|
||||
case 1:
|
||||
intel_pt_insn->rel = insn->immediate.value;
|
||||
break;
|
||||
case 2:
|
||||
intel_pt_insn->rel =
|
||||
bswap_16((short)insn->immediate.value);
|
||||
break;
|
||||
case 4:
|
||||
intel_pt_insn->rel = bswap_32(insn->immediate.value);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
intel_pt_insn->rel = insn->immediate.value;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
|
||||
struct intel_pt_insn *intel_pt_insn)
|
||||
{
|
||||
struct insn insn;
|
||||
|
||||
insn_init(&insn, buf, len, x86_64);
|
||||
insn_get_length(&insn);
|
||||
if (!insn_complete(&insn) || insn.length > len)
|
||||
return -1;
|
||||
intel_pt_insn_decoder(&insn, intel_pt_insn);
|
||||
if (insn.length < INTEL_PT_INSN_DBG_BUF_SZ)
|
||||
memcpy(intel_pt_insn->buf, buf, insn.length);
|
||||
else
|
||||
memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_DBG_BUF_SZ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *branch_name[] = {
|
||||
[INTEL_PT_OP_OTHER] = "Other",
|
||||
[INTEL_PT_OP_CALL] = "Call",
|
||||
[INTEL_PT_OP_RET] = "Ret",
|
||||
[INTEL_PT_OP_JCC] = "Jcc",
|
||||
[INTEL_PT_OP_JMP] = "Jmp",
|
||||
[INTEL_PT_OP_LOOP] = "Loop",
|
||||
[INTEL_PT_OP_IRET] = "IRet",
|
||||
[INTEL_PT_OP_INT] = "Int",
|
||||
[INTEL_PT_OP_SYSCALL] = "Syscall",
|
||||
[INTEL_PT_OP_SYSRET] = "Sysret",
|
||||
};
|
||||
|
||||
const char *intel_pt_insn_name(enum intel_pt_insn_op op)
|
||||
{
|
||||
return branch_name[op];
|
||||
}
|
||||
|
||||
int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
|
||||
size_t buf_len)
|
||||
{
|
||||
switch (intel_pt_insn->branch) {
|
||||
case INTEL_PT_BR_CONDITIONAL:
|
||||
case INTEL_PT_BR_UNCONDITIONAL:
|
||||
return snprintf(buf, buf_len, "%s %s%d",
|
||||
intel_pt_insn_name(intel_pt_insn->op),
|
||||
intel_pt_insn->rel > 0 ? "+" : "",
|
||||
intel_pt_insn->rel);
|
||||
case INTEL_PT_BR_NO_BRANCH:
|
||||
case INTEL_PT_BR_INDIRECT:
|
||||
return snprintf(buf, buf_len, "%s",
|
||||
intel_pt_insn_name(intel_pt_insn->op));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t intel_pt_insn_max_size(void)
|
||||
{
|
||||
return MAX_INSN_SIZE;
|
||||
}
|
||||
|
||||
int intel_pt_insn_type(enum intel_pt_insn_op op)
|
||||
{
|
||||
switch (op) {
|
||||
case INTEL_PT_OP_OTHER:
|
||||
return 0;
|
||||
case INTEL_PT_OP_CALL:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL;
|
||||
case INTEL_PT_OP_RET:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN;
|
||||
case INTEL_PT_OP_JCC:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL;
|
||||
case INTEL_PT_OP_JMP:
|
||||
return PERF_IP_FLAG_BRANCH;
|
||||
case INTEL_PT_OP_LOOP:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL;
|
||||
case INTEL_PT_OP_IRET:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN |
|
||||
PERF_IP_FLAG_INTERRUPT;
|
||||
case INTEL_PT_OP_INT:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |
|
||||
PERF_IP_FLAG_INTERRUPT;
|
||||
case INTEL_PT_OP_SYSCALL:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |
|
||||
PERF_IP_FLAG_SYSCALLRET;
|
||||
case INTEL_PT_OP_SYSRET:
|
||||
return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN |
|
||||
PERF_IP_FLAG_SYSCALLRET;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* intel_pt_insn_decoder.h: Intel Processor Trace support
|
||||
* Copyright (c) 2013-2014, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE__INTEL_PT_INSN_DECODER_H__
|
||||
#define INCLUDE__INTEL_PT_INSN_DECODER_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define INTEL_PT_INSN_DESC_MAX 32
|
||||
#define INTEL_PT_INSN_DBG_BUF_SZ 16
|
||||
|
||||
enum intel_pt_insn_op {
|
||||
INTEL_PT_OP_OTHER,
|
||||
INTEL_PT_OP_CALL,
|
||||
INTEL_PT_OP_RET,
|
||||
INTEL_PT_OP_JCC,
|
||||
INTEL_PT_OP_JMP,
|
||||
INTEL_PT_OP_LOOP,
|
||||
INTEL_PT_OP_IRET,
|
||||
INTEL_PT_OP_INT,
|
||||
INTEL_PT_OP_SYSCALL,
|
||||
INTEL_PT_OP_SYSRET,
|
||||
};
|
||||
|
||||
enum intel_pt_insn_branch {
|
||||
INTEL_PT_BR_NO_BRANCH,
|
||||
INTEL_PT_BR_INDIRECT,
|
||||
INTEL_PT_BR_CONDITIONAL,
|
||||
INTEL_PT_BR_UNCONDITIONAL,
|
||||
};
|
||||
|
||||
struct intel_pt_insn {
|
||||
enum intel_pt_insn_op op;
|
||||
enum intel_pt_insn_branch branch;
|
||||
int length;
|
||||
int32_t rel;
|
||||
unsigned char buf[INTEL_PT_INSN_DBG_BUF_SZ];
|
||||
};
|
||||
|
||||
int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
|
||||
struct intel_pt_insn *intel_pt_insn);
|
||||
|
||||
const char *intel_pt_insn_name(enum intel_pt_insn_op op);
|
||||
|
||||
int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
|
||||
size_t buf_len);
|
||||
|
||||
size_t intel_pt_insn_max_size(void);
|
||||
|
||||
int intel_pt_insn_type(enum intel_pt_insn_op op);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,970 @@
|
|||
# x86 Opcode Maps
|
||||
#
|
||||
# This is (mostly) based on following documentations.
|
||||
# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C
|
||||
# (#326018-047US, June 2013)
|
||||
#
|
||||
#<Opcode maps>
|
||||
# Table: table-name
|
||||
# Referrer: escaped-name
|
||||
# AVXcode: avx-code
|
||||
# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
|
||||
# (or)
|
||||
# opcode: escape # escaped-name
|
||||
# EndTable
|
||||
#
|
||||
#<group maps>
|
||||
# GrpTable: GrpXXX
|
||||
# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...]
|
||||
# EndTable
|
||||
#
|
||||
# AVX Superscripts
|
||||
# (v): this opcode requires VEX prefix.
|
||||
# (v1): this opcode only supports 128bit VEX.
|
||||
#
|
||||
# Last Prefix Superscripts
|
||||
# - (66): the last prefix is 0x66
|
||||
# - (F3): the last prefix is 0xF3
|
||||
# - (F2): the last prefix is 0xF2
|
||||
# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case)
|
||||
# - (66&F2): Both 0x66 and 0xF2 prefixes are specified.
|
||||
|
||||
Table: one byte opcode
|
||||
Referrer:
|
||||
AVXcode:
|
||||
# 0x00 - 0x0f
|
||||
00: ADD Eb,Gb
|
||||
01: ADD Ev,Gv
|
||||
02: ADD Gb,Eb
|
||||
03: ADD Gv,Ev
|
||||
04: ADD AL,Ib
|
||||
05: ADD rAX,Iz
|
||||
06: PUSH ES (i64)
|
||||
07: POP ES (i64)
|
||||
08: OR Eb,Gb
|
||||
09: OR Ev,Gv
|
||||
0a: OR Gb,Eb
|
||||
0b: OR Gv,Ev
|
||||
0c: OR AL,Ib
|
||||
0d: OR rAX,Iz
|
||||
0e: PUSH CS (i64)
|
||||
0f: escape # 2-byte escape
|
||||
# 0x10 - 0x1f
|
||||
10: ADC Eb,Gb
|
||||
11: ADC Ev,Gv
|
||||
12: ADC Gb,Eb
|
||||
13: ADC Gv,Ev
|
||||
14: ADC AL,Ib
|
||||
15: ADC rAX,Iz
|
||||
16: PUSH SS (i64)
|
||||
17: POP SS (i64)
|
||||
18: SBB Eb,Gb
|
||||
19: SBB Ev,Gv
|
||||
1a: SBB Gb,Eb
|
||||
1b: SBB Gv,Ev
|
||||
1c: SBB AL,Ib
|
||||
1d: SBB rAX,Iz
|
||||
1e: PUSH DS (i64)
|
||||
1f: POP DS (i64)
|
||||
# 0x20 - 0x2f
|
||||
20: AND Eb,Gb
|
||||
21: AND Ev,Gv
|
||||
22: AND Gb,Eb
|
||||
23: AND Gv,Ev
|
||||
24: AND AL,Ib
|
||||
25: AND rAx,Iz
|
||||
26: SEG=ES (Prefix)
|
||||
27: DAA (i64)
|
||||
28: SUB Eb,Gb
|
||||
29: SUB Ev,Gv
|
||||
2a: SUB Gb,Eb
|
||||
2b: SUB Gv,Ev
|
||||
2c: SUB AL,Ib
|
||||
2d: SUB rAX,Iz
|
||||
2e: SEG=CS (Prefix)
|
||||
2f: DAS (i64)
|
||||
# 0x30 - 0x3f
|
||||
30: XOR Eb,Gb
|
||||
31: XOR Ev,Gv
|
||||
32: XOR Gb,Eb
|
||||
33: XOR Gv,Ev
|
||||
34: XOR AL,Ib
|
||||
35: XOR rAX,Iz
|
||||
36: SEG=SS (Prefix)
|
||||
37: AAA (i64)
|
||||
38: CMP Eb,Gb
|
||||
39: CMP Ev,Gv
|
||||
3a: CMP Gb,Eb
|
||||
3b: CMP Gv,Ev
|
||||
3c: CMP AL,Ib
|
||||
3d: CMP rAX,Iz
|
||||
3e: SEG=DS (Prefix)
|
||||
3f: AAS (i64)
|
||||
# 0x40 - 0x4f
|
||||
40: INC eAX (i64) | REX (o64)
|
||||
41: INC eCX (i64) | REX.B (o64)
|
||||
42: INC eDX (i64) | REX.X (o64)
|
||||
43: INC eBX (i64) | REX.XB (o64)
|
||||
44: INC eSP (i64) | REX.R (o64)
|
||||
45: INC eBP (i64) | REX.RB (o64)
|
||||
46: INC eSI (i64) | REX.RX (o64)
|
||||
47: INC eDI (i64) | REX.RXB (o64)
|
||||
48: DEC eAX (i64) | REX.W (o64)
|
||||
49: DEC eCX (i64) | REX.WB (o64)
|
||||
4a: DEC eDX (i64) | REX.WX (o64)
|
||||
4b: DEC eBX (i64) | REX.WXB (o64)
|
||||
4c: DEC eSP (i64) | REX.WR (o64)
|
||||
4d: DEC eBP (i64) | REX.WRB (o64)
|
||||
4e: DEC eSI (i64) | REX.WRX (o64)
|
||||
4f: DEC eDI (i64) | REX.WRXB (o64)
|
||||
# 0x50 - 0x5f
|
||||
50: PUSH rAX/r8 (d64)
|
||||
51: PUSH rCX/r9 (d64)
|
||||
52: PUSH rDX/r10 (d64)
|
||||
53: PUSH rBX/r11 (d64)
|
||||
54: PUSH rSP/r12 (d64)
|
||||
55: PUSH rBP/r13 (d64)
|
||||
56: PUSH rSI/r14 (d64)
|
||||
57: PUSH rDI/r15 (d64)
|
||||
58: POP rAX/r8 (d64)
|
||||
59: POP rCX/r9 (d64)
|
||||
5a: POP rDX/r10 (d64)
|
||||
5b: POP rBX/r11 (d64)
|
||||
5c: POP rSP/r12 (d64)
|
||||
5d: POP rBP/r13 (d64)
|
||||
5e: POP rSI/r14 (d64)
|
||||
5f: POP rDI/r15 (d64)
|
||||
# 0x60 - 0x6f
|
||||
60: PUSHA/PUSHAD (i64)
|
||||
61: POPA/POPAD (i64)
|
||||
62: BOUND Gv,Ma (i64)
|
||||
63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64)
|
||||
64: SEG=FS (Prefix)
|
||||
65: SEG=GS (Prefix)
|
||||
66: Operand-Size (Prefix)
|
||||
67: Address-Size (Prefix)
|
||||
68: PUSH Iz (d64)
|
||||
69: IMUL Gv,Ev,Iz
|
||||
6a: PUSH Ib (d64)
|
||||
6b: IMUL Gv,Ev,Ib
|
||||
6c: INS/INSB Yb,DX
|
||||
6d: INS/INSW/INSD Yz,DX
|
||||
6e: OUTS/OUTSB DX,Xb
|
||||
6f: OUTS/OUTSW/OUTSD DX,Xz
|
||||
# 0x70 - 0x7f
|
||||
70: JO Jb
|
||||
71: JNO Jb
|
||||
72: JB/JNAE/JC Jb
|
||||
73: JNB/JAE/JNC Jb
|
||||
74: JZ/JE Jb
|
||||
75: JNZ/JNE Jb
|
||||
76: JBE/JNA Jb
|
||||
77: JNBE/JA Jb
|
||||
78: JS Jb
|
||||
79: JNS Jb
|
||||
7a: JP/JPE Jb
|
||||
7b: JNP/JPO Jb
|
||||
7c: JL/JNGE Jb
|
||||
7d: JNL/JGE Jb
|
||||
7e: JLE/JNG Jb
|
||||
7f: JNLE/JG Jb
|
||||
# 0x80 - 0x8f
|
||||
80: Grp1 Eb,Ib (1A)
|
||||
81: Grp1 Ev,Iz (1A)
|
||||
82: Grp1 Eb,Ib (1A),(i64)
|
||||
83: Grp1 Ev,Ib (1A)
|
||||
84: TEST Eb,Gb
|
||||
85: TEST Ev,Gv
|
||||
86: XCHG Eb,Gb
|
||||
87: XCHG Ev,Gv
|
||||
88: MOV Eb,Gb
|
||||
89: MOV Ev,Gv
|
||||
8a: MOV Gb,Eb
|
||||
8b: MOV Gv,Ev
|
||||
8c: MOV Ev,Sw
|
||||
8d: LEA Gv,M
|
||||
8e: MOV Sw,Ew
|
||||
8f: Grp1A (1A) | POP Ev (d64)
|
||||
# 0x90 - 0x9f
|
||||
90: NOP | PAUSE (F3) | XCHG r8,rAX
|
||||
91: XCHG rCX/r9,rAX
|
||||
92: XCHG rDX/r10,rAX
|
||||
93: XCHG rBX/r11,rAX
|
||||
94: XCHG rSP/r12,rAX
|
||||
95: XCHG rBP/r13,rAX
|
||||
96: XCHG rSI/r14,rAX
|
||||
97: XCHG rDI/r15,rAX
|
||||
98: CBW/CWDE/CDQE
|
||||
99: CWD/CDQ/CQO
|
||||
9a: CALLF Ap (i64)
|
||||
9b: FWAIT/WAIT
|
||||
9c: PUSHF/D/Q Fv (d64)
|
||||
9d: POPF/D/Q Fv (d64)
|
||||
9e: SAHF
|
||||
9f: LAHF
|
||||
# 0xa0 - 0xaf
|
||||
a0: MOV AL,Ob
|
||||
a1: MOV rAX,Ov
|
||||
a2: MOV Ob,AL
|
||||
a3: MOV Ov,rAX
|
||||
a4: MOVS/B Yb,Xb
|
||||
a5: MOVS/W/D/Q Yv,Xv
|
||||
a6: CMPS/B Xb,Yb
|
||||
a7: CMPS/W/D Xv,Yv
|
||||
a8: TEST AL,Ib
|
||||
a9: TEST rAX,Iz
|
||||
aa: STOS/B Yb,AL
|
||||
ab: STOS/W/D/Q Yv,rAX
|
||||
ac: LODS/B AL,Xb
|
||||
ad: LODS/W/D/Q rAX,Xv
|
||||
ae: SCAS/B AL,Yb
|
||||
# Note: The May 2011 Intel manual shows Xv for the second parameter of the
|
||||
# next instruction but Yv is correct
|
||||
af: SCAS/W/D/Q rAX,Yv
|
||||
# 0xb0 - 0xbf
|
||||
b0: MOV AL/R8L,Ib
|
||||
b1: MOV CL/R9L,Ib
|
||||
b2: MOV DL/R10L,Ib
|
||||
b3: MOV BL/R11L,Ib
|
||||
b4: MOV AH/R12L,Ib
|
||||
b5: MOV CH/R13L,Ib
|
||||
b6: MOV DH/R14L,Ib
|
||||
b7: MOV BH/R15L,Ib
|
||||
b8: MOV rAX/r8,Iv
|
||||
b9: MOV rCX/r9,Iv
|
||||
ba: MOV rDX/r10,Iv
|
||||
bb: MOV rBX/r11,Iv
|
||||
bc: MOV rSP/r12,Iv
|
||||
bd: MOV rBP/r13,Iv
|
||||
be: MOV rSI/r14,Iv
|
||||
bf: MOV rDI/r15,Iv
|
||||
# 0xc0 - 0xcf
|
||||
c0: Grp2 Eb,Ib (1A)
|
||||
c1: Grp2 Ev,Ib (1A)
|
||||
c2: RETN Iw (f64)
|
||||
c3: RETN
|
||||
c4: LES Gz,Mp (i64) | VEX+2byte (Prefix)
|
||||
c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix)
|
||||
c6: Grp11A Eb,Ib (1A)
|
||||
c7: Grp11B Ev,Iz (1A)
|
||||
c8: ENTER Iw,Ib
|
||||
c9: LEAVE (d64)
|
||||
ca: RETF Iw
|
||||
cb: RETF
|
||||
cc: INT3
|
||||
cd: INT Ib
|
||||
ce: INTO (i64)
|
||||
cf: IRET/D/Q
|
||||
# 0xd0 - 0xdf
|
||||
d0: Grp2 Eb,1 (1A)
|
||||
d1: Grp2 Ev,1 (1A)
|
||||
d2: Grp2 Eb,CL (1A)
|
||||
d3: Grp2 Ev,CL (1A)
|
||||
d4: AAM Ib (i64)
|
||||
d5: AAD Ib (i64)
|
||||
d6:
|
||||
d7: XLAT/XLATB
|
||||
d8: ESC
|
||||
d9: ESC
|
||||
da: ESC
|
||||
db: ESC
|
||||
dc: ESC
|
||||
dd: ESC
|
||||
de: ESC
|
||||
df: ESC
|
||||
# 0xe0 - 0xef
|
||||
# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix
|
||||
# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation
|
||||
# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD.
|
||||
e0: LOOPNE/LOOPNZ Jb (f64)
|
||||
e1: LOOPE/LOOPZ Jb (f64)
|
||||
e2: LOOP Jb (f64)
|
||||
e3: JrCXZ Jb (f64)
|
||||
e4: IN AL,Ib
|
||||
e5: IN eAX,Ib
|
||||
e6: OUT Ib,AL
|
||||
e7: OUT Ib,eAX
|
||||
# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset
|
||||
# in "near" jumps and calls is 16-bit. For CALL,
|
||||
# push of return address is 16-bit wide, RSP is decremented by 2
|
||||
# but is not truncated to 16 bits, unlike RIP.
|
||||
e8: CALL Jz (f64)
|
||||
e9: JMP-near Jz (f64)
|
||||
ea: JMP-far Ap (i64)
|
||||
eb: JMP-short Jb (f64)
|
||||
ec: IN AL,DX
|
||||
ed: IN eAX,DX
|
||||
ee: OUT DX,AL
|
||||
ef: OUT DX,eAX
|
||||
# 0xf0 - 0xff
|
||||
f0: LOCK (Prefix)
|
||||
f1:
|
||||
f2: REPNE (Prefix) | XACQUIRE (Prefix)
|
||||
f3: REP/REPE (Prefix) | XRELEASE (Prefix)
|
||||
f4: HLT
|
||||
f5: CMC
|
||||
f6: Grp3_1 Eb (1A)
|
||||
f7: Grp3_2 Ev (1A)
|
||||
f8: CLC
|
||||
f9: STC
|
||||
fa: CLI
|
||||
fb: STI
|
||||
fc: CLD
|
||||
fd: STD
|
||||
fe: Grp4 (1A)
|
||||
ff: Grp5 (1A)
|
||||
EndTable
|
||||
|
||||
Table: 2-byte opcode (0x0f)
|
||||
Referrer: 2-byte escape
|
||||
AVXcode: 1
|
||||
# 0x0f 0x00-0x0f
|
||||
00: Grp6 (1A)
|
||||
01: Grp7 (1A)
|
||||
02: LAR Gv,Ew
|
||||
03: LSL Gv,Ew
|
||||
04:
|
||||
05: SYSCALL (o64)
|
||||
06: CLTS
|
||||
07: SYSRET (o64)
|
||||
08: INVD
|
||||
09: WBINVD
|
||||
0a:
|
||||
0b: UD2 (1B)
|
||||
0c:
|
||||
# AMD's prefetch group. Intel supports prefetchw(/1) only.
|
||||
0d: GrpP
|
||||
0e: FEMMS
|
||||
# 3DNow! uses the last imm byte as opcode extension.
|
||||
0f: 3DNow! Pq,Qq,Ib
|
||||
# 0x0f 0x10-0x1f
|
||||
# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands
|
||||
# but it actually has operands. And also, vmovss and vmovsd only accept 128bit.
|
||||
# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form.
|
||||
# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming
|
||||
# Reference A.1
|
||||
10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1)
|
||||
11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1)
|
||||
12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2)
|
||||
13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1)
|
||||
14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66)
|
||||
15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66)
|
||||
16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3)
|
||||
17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1)
|
||||
18: Grp16 (1A)
|
||||
19:
|
||||
1a: BNDCL Ev,Gv | BNDCU Ev,Gv | BNDMOV Gv,Ev | BNDLDX Gv,Ev,Gv
|
||||
1b: BNDCN Ev,Gv | BNDMOV Ev,Gv | BNDMK Gv,Ev | BNDSTX Ev,GV,Gv
|
||||
1c:
|
||||
1d:
|
||||
1e:
|
||||
1f: NOP Ev
|
||||
# 0x0f 0x20-0x2f
|
||||
20: MOV Rd,Cd
|
||||
21: MOV Rd,Dd
|
||||
22: MOV Cd,Rd
|
||||
23: MOV Dd,Rd
|
||||
24:
|
||||
25:
|
||||
26:
|
||||
27:
|
||||
28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66)
|
||||
29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66)
|
||||
2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1)
|
||||
2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66)
|
||||
2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1)
|
||||
2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1)
|
||||
2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1)
|
||||
2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1)
|
||||
# 0x0f 0x30-0x3f
|
||||
30: WRMSR
|
||||
31: RDTSC
|
||||
32: RDMSR
|
||||
33: RDPMC
|
||||
34: SYSENTER
|
||||
35: SYSEXIT
|
||||
36:
|
||||
37: GETSEC
|
||||
38: escape # 3-byte escape 1
|
||||
39:
|
||||
3a: escape # 3-byte escape 2
|
||||
3b:
|
||||
3c:
|
||||
3d:
|
||||
3e:
|
||||
3f:
|
||||
# 0x0f 0x40-0x4f
|
||||
40: CMOVO Gv,Ev
|
||||
41: CMOVNO Gv,Ev
|
||||
42: CMOVB/C/NAE Gv,Ev
|
||||
43: CMOVAE/NB/NC Gv,Ev
|
||||
44: CMOVE/Z Gv,Ev
|
||||
45: CMOVNE/NZ Gv,Ev
|
||||
46: CMOVBE/NA Gv,Ev
|
||||
47: CMOVA/NBE Gv,Ev
|
||||
48: CMOVS Gv,Ev
|
||||
49: CMOVNS Gv,Ev
|
||||
4a: CMOVP/PE Gv,Ev
|
||||
4b: CMOVNP/PO Gv,Ev
|
||||
4c: CMOVL/NGE Gv,Ev
|
||||
4d: CMOVNL/GE Gv,Ev
|
||||
4e: CMOVLE/NG Gv,Ev
|
||||
4f: CMOVNLE/G Gv,Ev
|
||||
# 0x0f 0x50-0x5f
|
||||
50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66)
|
||||
51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1)
|
||||
52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1)
|
||||
53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1)
|
||||
54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66)
|
||||
55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66)
|
||||
56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66)
|
||||
57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66)
|
||||
58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1)
|
||||
59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1)
|
||||
5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1)
|
||||
5b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3)
|
||||
5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1)
|
||||
5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1)
|
||||
5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1)
|
||||
5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1)
|
||||
# 0x0f 0x60-0x6f
|
||||
60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1)
|
||||
61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1)
|
||||
62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1)
|
||||
63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1)
|
||||
64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1)
|
||||
65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1)
|
||||
66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1)
|
||||
67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1)
|
||||
68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1)
|
||||
69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1)
|
||||
6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1)
|
||||
6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1)
|
||||
6c: vpunpcklqdq Vx,Hx,Wx (66),(v1)
|
||||
6d: vpunpckhqdq Vx,Hx,Wx (66),(v1)
|
||||
6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1)
|
||||
6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3)
|
||||
# 0x0f 0x70-0x7f
|
||||
70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1)
|
||||
71: Grp12 (1A)
|
||||
72: Grp13 (1A)
|
||||
73: Grp14 (1A)
|
||||
74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1)
|
||||
75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1)
|
||||
76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1)
|
||||
# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX.
|
||||
77: emms | vzeroupper | vzeroall
|
||||
78: VMREAD Ey,Gy
|
||||
79: VMWRITE Gy,Ey
|
||||
7a:
|
||||
7b:
|
||||
7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2)
|
||||
7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2)
|
||||
7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1)
|
||||
7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3)
|
||||
# 0x0f 0x80-0x8f
|
||||
# Note: "forced64" is Intel CPU behavior (see comment about CALL insn).
|
||||
80: JO Jz (f64)
|
||||
81: JNO Jz (f64)
|
||||
82: JB/JC/JNAE Jz (f64)
|
||||
83: JAE/JNB/JNC Jz (f64)
|
||||
84: JE/JZ Jz (f64)
|
||||
85: JNE/JNZ Jz (f64)
|
||||
86: JBE/JNA Jz (f64)
|
||||
87: JA/JNBE Jz (f64)
|
||||
88: JS Jz (f64)
|
||||
89: JNS Jz (f64)
|
||||
8a: JP/JPE Jz (f64)
|
||||
8b: JNP/JPO Jz (f64)
|
||||
8c: JL/JNGE Jz (f64)
|
||||
8d: JNL/JGE Jz (f64)
|
||||
8e: JLE/JNG Jz (f64)
|
||||
8f: JNLE/JG Jz (f64)
|
||||
# 0x0f 0x90-0x9f
|
||||
90: SETO Eb
|
||||
91: SETNO Eb
|
||||
92: SETB/C/NAE Eb
|
||||
93: SETAE/NB/NC Eb
|
||||
94: SETE/Z Eb
|
||||
95: SETNE/NZ Eb
|
||||
96: SETBE/NA Eb
|
||||
97: SETA/NBE Eb
|
||||
98: SETS Eb
|
||||
99: SETNS Eb
|
||||
9a: SETP/PE Eb
|
||||
9b: SETNP/PO Eb
|
||||
9c: SETL/NGE Eb
|
||||
9d: SETNL/GE Eb
|
||||
9e: SETLE/NG Eb
|
||||
9f: SETNLE/G Eb
|
||||
# 0x0f 0xa0-0xaf
|
||||
a0: PUSH FS (d64)
|
||||
a1: POP FS (d64)
|
||||
a2: CPUID
|
||||
a3: BT Ev,Gv
|
||||
a4: SHLD Ev,Gv,Ib
|
||||
a5: SHLD Ev,Gv,CL
|
||||
a6: GrpPDLK
|
||||
a7: GrpRNG
|
||||
a8: PUSH GS (d64)
|
||||
a9: POP GS (d64)
|
||||
aa: RSM
|
||||
ab: BTS Ev,Gv
|
||||
ac: SHRD Ev,Gv,Ib
|
||||
ad: SHRD Ev,Gv,CL
|
||||
ae: Grp15 (1A),(1C)
|
||||
af: IMUL Gv,Ev
|
||||
# 0x0f 0xb0-0xbf
|
||||
b0: CMPXCHG Eb,Gb
|
||||
b1: CMPXCHG Ev,Gv
|
||||
b2: LSS Gv,Mp
|
||||
b3: BTR Ev,Gv
|
||||
b4: LFS Gv,Mp
|
||||
b5: LGS Gv,Mp
|
||||
b6: MOVZX Gv,Eb
|
||||
b7: MOVZX Gv,Ew
|
||||
b8: JMPE (!F3) | POPCNT Gv,Ev (F3)
|
||||
b9: Grp10 (1A)
|
||||
ba: Grp8 Ev,Ib (1A)
|
||||
bb: BTC Ev,Gv
|
||||
bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3)
|
||||
bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3)
|
||||
be: MOVSX Gv,Eb
|
||||
bf: MOVSX Gv,Ew
|
||||
# 0x0f 0xc0-0xcf
|
||||
c0: XADD Eb,Gb
|
||||
c1: XADD Ev,Gv
|
||||
c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1)
|
||||
c3: movnti My,Gy
|
||||
c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1)
|
||||
c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1)
|
||||
c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66)
|
||||
c7: Grp9 (1A)
|
||||
c8: BSWAP RAX/EAX/R8/R8D
|
||||
c9: BSWAP RCX/ECX/R9/R9D
|
||||
ca: BSWAP RDX/EDX/R10/R10D
|
||||
cb: BSWAP RBX/EBX/R11/R11D
|
||||
cc: BSWAP RSP/ESP/R12/R12D
|
||||
cd: BSWAP RBP/EBP/R13/R13D
|
||||
ce: BSWAP RSI/ESI/R14/R14D
|
||||
cf: BSWAP RDI/EDI/R15/R15D
|
||||
# 0x0f 0xd0-0xdf
|
||||
d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2)
|
||||
d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1)
|
||||
d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1)
|
||||
d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1)
|
||||
d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1)
|
||||
d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1)
|
||||
d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2)
|
||||
d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1)
|
||||
d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1)
|
||||
d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1)
|
||||
da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1)
|
||||
db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1)
|
||||
dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1)
|
||||
dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1)
|
||||
de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1)
|
||||
df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1)
|
||||
# 0x0f 0xe0-0xef
|
||||
e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1)
|
||||
e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1)
|
||||
e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1)
|
||||
e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1)
|
||||
e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1)
|
||||
e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1)
|
||||
e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2)
|
||||
e7: movntq Mq,Pq | vmovntdq Mx,Vx (66)
|
||||
e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1)
|
||||
e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1)
|
||||
ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1)
|
||||
eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1)
|
||||
ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1)
|
||||
ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1)
|
||||
ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1)
|
||||
ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1)
|
||||
# 0x0f 0xf0-0xff
|
||||
f0: vlddqu Vx,Mx (F2)
|
||||
f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1)
|
||||
f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1)
|
||||
f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1)
|
||||
f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1)
|
||||
f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1)
|
||||
f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1)
|
||||
f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1)
|
||||
f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1)
|
||||
f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1)
|
||||
fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1)
|
||||
fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1)
|
||||
fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1)
|
||||
fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1)
|
||||
fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1)
|
||||
ff:
|
||||
EndTable
|
||||
|
||||
Table: 3-byte opcode 1 (0x0f 0x38)
|
||||
Referrer: 3-byte escape 1
|
||||
AVXcode: 2
|
||||
# 0x0f 0x38 0x00-0x0f
|
||||
00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1)
|
||||
01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1)
|
||||
02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1)
|
||||
03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1)
|
||||
04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1)
|
||||
05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1)
|
||||
06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1)
|
||||
07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1)
|
||||
08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1)
|
||||
09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1)
|
||||
0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1)
|
||||
0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1)
|
||||
0c: vpermilps Vx,Hx,Wx (66),(v)
|
||||
0d: vpermilpd Vx,Hx,Wx (66),(v)
|
||||
0e: vtestps Vx,Wx (66),(v)
|
||||
0f: vtestpd Vx,Wx (66),(v)
|
||||
# 0x0f 0x38 0x10-0x1f
|
||||
10: pblendvb Vdq,Wdq (66)
|
||||
11:
|
||||
12:
|
||||
13: vcvtph2ps Vx,Wx,Ib (66),(v)
|
||||
14: blendvps Vdq,Wdq (66)
|
||||
15: blendvpd Vdq,Wdq (66)
|
||||
16: vpermps Vqq,Hqq,Wqq (66),(v)
|
||||
17: vptest Vx,Wx (66)
|
||||
18: vbroadcastss Vx,Wd (66),(v)
|
||||
19: vbroadcastsd Vqq,Wq (66),(v)
|
||||
1a: vbroadcastf128 Vqq,Mdq (66),(v)
|
||||
1b:
|
||||
1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1)
|
||||
1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1)
|
||||
1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1)
|
||||
1f:
|
||||
# 0x0f 0x38 0x20-0x2f
|
||||
20: vpmovsxbw Vx,Ux/Mq (66),(v1)
|
||||
21: vpmovsxbd Vx,Ux/Md (66),(v1)
|
||||
22: vpmovsxbq Vx,Ux/Mw (66),(v1)
|
||||
23: vpmovsxwd Vx,Ux/Mq (66),(v1)
|
||||
24: vpmovsxwq Vx,Ux/Md (66),(v1)
|
||||
25: vpmovsxdq Vx,Ux/Mq (66),(v1)
|
||||
26:
|
||||
27:
|
||||
28: vpmuldq Vx,Hx,Wx (66),(v1)
|
||||
29: vpcmpeqq Vx,Hx,Wx (66),(v1)
|
||||
2a: vmovntdqa Vx,Mx (66),(v1)
|
||||
2b: vpackusdw Vx,Hx,Wx (66),(v1)
|
||||
2c: vmaskmovps Vx,Hx,Mx (66),(v)
|
||||
2d: vmaskmovpd Vx,Hx,Mx (66),(v)
|
||||
2e: vmaskmovps Mx,Hx,Vx (66),(v)
|
||||
2f: vmaskmovpd Mx,Hx,Vx (66),(v)
|
||||
# 0x0f 0x38 0x30-0x3f
|
||||
30: vpmovzxbw Vx,Ux/Mq (66),(v1)
|
||||
31: vpmovzxbd Vx,Ux/Md (66),(v1)
|
||||
32: vpmovzxbq Vx,Ux/Mw (66),(v1)
|
||||
33: vpmovzxwd Vx,Ux/Mq (66),(v1)
|
||||
34: vpmovzxwq Vx,Ux/Md (66),(v1)
|
||||
35: vpmovzxdq Vx,Ux/Mq (66),(v1)
|
||||
36: vpermd Vqq,Hqq,Wqq (66),(v)
|
||||
37: vpcmpgtq Vx,Hx,Wx (66),(v1)
|
||||
38: vpminsb Vx,Hx,Wx (66),(v1)
|
||||
39: vpminsd Vx,Hx,Wx (66),(v1)
|
||||
3a: vpminuw Vx,Hx,Wx (66),(v1)
|
||||
3b: vpminud Vx,Hx,Wx (66),(v1)
|
||||
3c: vpmaxsb Vx,Hx,Wx (66),(v1)
|
||||
3d: vpmaxsd Vx,Hx,Wx (66),(v1)
|
||||
3e: vpmaxuw Vx,Hx,Wx (66),(v1)
|
||||
3f: vpmaxud Vx,Hx,Wx (66),(v1)
|
||||
# 0x0f 0x38 0x40-0x8f
|
||||
40: vpmulld Vx,Hx,Wx (66),(v1)
|
||||
41: vphminposuw Vdq,Wdq (66),(v1)
|
||||
42:
|
||||
43:
|
||||
44:
|
||||
45: vpsrlvd/q Vx,Hx,Wx (66),(v)
|
||||
46: vpsravd Vx,Hx,Wx (66),(v)
|
||||
47: vpsllvd/q Vx,Hx,Wx (66),(v)
|
||||
# Skip 0x48-0x57
|
||||
58: vpbroadcastd Vx,Wx (66),(v)
|
||||
59: vpbroadcastq Vx,Wx (66),(v)
|
||||
5a: vbroadcasti128 Vqq,Mdq (66),(v)
|
||||
# Skip 0x5b-0x77
|
||||
78: vpbroadcastb Vx,Wx (66),(v)
|
||||
79: vpbroadcastw Vx,Wx (66),(v)
|
||||
# Skip 0x7a-0x7f
|
||||
80: INVEPT Gy,Mdq (66)
|
||||
81: INVPID Gy,Mdq (66)
|
||||
82: INVPCID Gy,Mdq (66)
|
||||
8c: vpmaskmovd/q Vx,Hx,Mx (66),(v)
|
||||
8e: vpmaskmovd/q Mx,Vx,Hx (66),(v)
|
||||
# 0x0f 0x38 0x90-0xbf (FMA)
|
||||
90: vgatherdd/q Vx,Hx,Wx (66),(v)
|
||||
91: vgatherqd/q Vx,Hx,Wx (66),(v)
|
||||
92: vgatherdps/d Vx,Hx,Wx (66),(v)
|
||||
93: vgatherqps/d Vx,Hx,Wx (66),(v)
|
||||
94:
|
||||
95:
|
||||
96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v)
|
||||
97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v)
|
||||
98: vfmadd132ps/d Vx,Hx,Wx (66),(v)
|
||||
99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
9a: vfmsub132ps/d Vx,Hx,Wx (66),(v)
|
||||
9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v)
|
||||
9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v)
|
||||
9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v)
|
||||
a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v)
|
||||
a8: vfmadd213ps/d Vx,Hx,Wx (66),(v)
|
||||
a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
aa: vfmsub213ps/d Vx,Hx,Wx (66),(v)
|
||||
ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v)
|
||||
ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v)
|
||||
af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v)
|
||||
b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v)
|
||||
b8: vfmadd231ps/d Vx,Hx,Wx (66),(v)
|
||||
b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
ba: vfmsub231ps/d Vx,Hx,Wx (66),(v)
|
||||
bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v)
|
||||
bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
be: vfnmsub231ps/d Vx,Hx,Wx (66),(v)
|
||||
bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1)
|
||||
# 0x0f 0x38 0xc0-0xff
|
||||
db: VAESIMC Vdq,Wdq (66),(v1)
|
||||
dc: VAESENC Vdq,Hdq,Wdq (66),(v1)
|
||||
dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1)
|
||||
de: VAESDEC Vdq,Hdq,Wdq (66),(v1)
|
||||
df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1)
|
||||
f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2)
|
||||
f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2)
|
||||
f2: ANDN Gy,By,Ey (v)
|
||||
f3: Grp17 (1A)
|
||||
f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v)
|
||||
f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v)
|
||||
f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v)
|
||||
EndTable
|
||||
|
||||
Table: 3-byte opcode 2 (0x0f 0x3a)
|
||||
Referrer: 3-byte escape 2
|
||||
AVXcode: 3
|
||||
# 0x0f 0x3a 0x00-0xff
|
||||
00: vpermq Vqq,Wqq,Ib (66),(v)
|
||||
01: vpermpd Vqq,Wqq,Ib (66),(v)
|
||||
02: vpblendd Vx,Hx,Wx,Ib (66),(v)
|
||||
03:
|
||||
04: vpermilps Vx,Wx,Ib (66),(v)
|
||||
05: vpermilpd Vx,Wx,Ib (66),(v)
|
||||
06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v)
|
||||
07:
|
||||
08: vroundps Vx,Wx,Ib (66)
|
||||
09: vroundpd Vx,Wx,Ib (66)
|
||||
0a: vroundss Vss,Wss,Ib (66),(v1)
|
||||
0b: vroundsd Vsd,Wsd,Ib (66),(v1)
|
||||
0c: vblendps Vx,Hx,Wx,Ib (66)
|
||||
0d: vblendpd Vx,Hx,Wx,Ib (66)
|
||||
0e: vpblendw Vx,Hx,Wx,Ib (66),(v1)
|
||||
0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1)
|
||||
14: vpextrb Rd/Mb,Vdq,Ib (66),(v1)
|
||||
15: vpextrw Rd/Mw,Vdq,Ib (66),(v1)
|
||||
16: vpextrd/q Ey,Vdq,Ib (66),(v1)
|
||||
17: vextractps Ed,Vdq,Ib (66),(v1)
|
||||
18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v)
|
||||
19: vextractf128 Wdq,Vqq,Ib (66),(v)
|
||||
1d: vcvtps2ph Wx,Vx,Ib (66),(v)
|
||||
20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1)
|
||||
21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1)
|
||||
22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1)
|
||||
38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v)
|
||||
39: vextracti128 Wdq,Vqq,Ib (66),(v)
|
||||
40: vdpps Vx,Hx,Wx,Ib (66)
|
||||
41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1)
|
||||
42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1)
|
||||
44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1)
|
||||
46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v)
|
||||
4a: vblendvps Vx,Hx,Wx,Lx (66),(v)
|
||||
4b: vblendvpd Vx,Hx,Wx,Lx (66),(v)
|
||||
4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1)
|
||||
60: vpcmpestrm Vdq,Wdq,Ib (66),(v1)
|
||||
61: vpcmpestri Vdq,Wdq,Ib (66),(v1)
|
||||
62: vpcmpistrm Vdq,Wdq,Ib (66),(v1)
|
||||
63: vpcmpistri Vdq,Wdq,Ib (66),(v1)
|
||||
df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1)
|
||||
f0: RORX Gy,Ey,Ib (F2),(v)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp1
|
||||
0: ADD
|
||||
1: OR
|
||||
2: ADC
|
||||
3: SBB
|
||||
4: AND
|
||||
5: SUB
|
||||
6: XOR
|
||||
7: CMP
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp1A
|
||||
0: POP
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp2
|
||||
0: ROL
|
||||
1: ROR
|
||||
2: RCL
|
||||
3: RCR
|
||||
4: SHL/SAL
|
||||
5: SHR
|
||||
6:
|
||||
7: SAR
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp3_1
|
||||
0: TEST Eb,Ib
|
||||
1:
|
||||
2: NOT Eb
|
||||
3: NEG Eb
|
||||
4: MUL AL,Eb
|
||||
5: IMUL AL,Eb
|
||||
6: DIV AL,Eb
|
||||
7: IDIV AL,Eb
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp3_2
|
||||
0: TEST Ev,Iz
|
||||
1:
|
||||
2: NOT Ev
|
||||
3: NEG Ev
|
||||
4: MUL rAX,Ev
|
||||
5: IMUL rAX,Ev
|
||||
6: DIV rAX,Ev
|
||||
7: IDIV rAX,Ev
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp4
|
||||
0: INC Eb
|
||||
1: DEC Eb
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp5
|
||||
0: INC Ev
|
||||
1: DEC Ev
|
||||
# Note: "forced64" is Intel CPU behavior (see comment about CALL insn).
|
||||
2: CALLN Ev (f64)
|
||||
3: CALLF Ep
|
||||
4: JMPN Ev (f64)
|
||||
5: JMPF Mp
|
||||
6: PUSH Ev (d64)
|
||||
7:
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp6
|
||||
0: SLDT Rv/Mw
|
||||
1: STR Rv/Mw
|
||||
2: LLDT Ew
|
||||
3: LTR Ew
|
||||
4: VERR Ew
|
||||
5: VERW Ew
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp7
|
||||
0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B)
|
||||
1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B)
|
||||
2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B)
|
||||
3: LIDT Ms
|
||||
4: SMSW Mw/Rv
|
||||
5:
|
||||
6: LMSW Ew
|
||||
7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp8
|
||||
4: BT
|
||||
5: BTS
|
||||
6: BTR
|
||||
7: BTC
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp9
|
||||
1: CMPXCHG8B/16B Mq/Mdq
|
||||
6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B)
|
||||
7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp10
|
||||
EndTable
|
||||
|
||||
# Grp11A and Grp11B are expressed as Grp11 in Intel SDM
|
||||
GrpTable: Grp11A
|
||||
0: MOV Eb,Ib
|
||||
7: XABORT Ib (000),(11B)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp11B
|
||||
0: MOV Eb,Iz
|
||||
7: XBEGIN Jz (000),(11B)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp12
|
||||
2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1)
|
||||
4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1)
|
||||
6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp13
|
||||
2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1)
|
||||
4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1)
|
||||
6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp14
|
||||
2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1)
|
||||
3: vpsrldq Hx,Ux,Ib (66),(11B),(v1)
|
||||
6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1)
|
||||
7: vpslldq Hx,Ux,Ib (66),(11B),(v1)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp15
|
||||
0: fxsave | RDFSBASE Ry (F3),(11B)
|
||||
1: fxstor | RDGSBASE Ry (F3),(11B)
|
||||
2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B)
|
||||
3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B)
|
||||
4: XSAVE
|
||||
5: XRSTOR | lfence (11B)
|
||||
6: XSAVEOPT | mfence (11B)
|
||||
7: clflush | sfence (11B)
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp16
|
||||
0: prefetch NTA
|
||||
1: prefetch T0
|
||||
2: prefetch T1
|
||||
3: prefetch T2
|
||||
EndTable
|
||||
|
||||
GrpTable: Grp17
|
||||
1: BLSR By,Ey (v)
|
||||
2: BLSMSK By,Ey (v)
|
||||
3: BLSI By,Ey (v)
|
||||
EndTable
|
||||
|
||||
# AMD's Prefetch Group
|
||||
GrpTable: GrpP
|
||||
0: PREFETCH
|
||||
1: PREFETCHW
|
||||
EndTable
|
||||
|
||||
GrpTable: GrpPDLK
|
||||
0: MONTMUL
|
||||
1: XSHA1
|
||||
2: XSHA2
|
||||
EndTable
|
||||
|
||||
GrpTable: GrpRNG
|
||||
0: xstore-rng
|
||||
1: xcrypt-ecb
|
||||
2: xcrypt-cbc
|
||||
4: xcrypt-cfb
|
||||
5: xcrypt-ofb
|
||||
EndTable
|
Загрузка…
Ссылка в новой задаче