From nobody Sat Apr 5 01:27:42 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=anarch128.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1739122165992103.25788236769256; Sun, 9 Feb 2025 09:29:25 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1thB6l-0004bF-L0; Sun, 09 Feb 2025 12:28:39 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thB6H-0004Wp-Qr for qemu-devel@nongnu.org; Sun, 09 Feb 2025 12:28:10 -0500 Received: from anarch128.org ([2001:4801:7825:104:be76:4eff:fe10:52ae]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1thB6B-0006LV-9O for qemu-devel@nongnu.org; Sun, 09 Feb 2025 12:28:07 -0500 Received: from localhost.localdomain (default-rdns.vocus.co.nz [202.150.110.104] (may be forged)) (authenticated bits=0) by anarch128.org (8.15.2/8.15.2/Debian-22+deb11u3) with ESMTPSA id 519HRdEr3380282 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Sun, 9 Feb 2025 17:27:54 GMT Authentication-Results: anarch128.org; auth=pass; dkim=pass (2048-bit rsa key sha256) header.d=anarch128.org header.i=@anarch128.org header.b=Xm/4vYbY header.a=rsa-sha256 header.s=100003; x-return-mx=pass header.domain=anarch128.org policy.is_org=yes (MX Records found: mail.anarch128.org); x-return-mx=pass smtp.domain=anarch128.org policy.is_org=yes (MX Records found: mail.anarch128.org) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=anarch128.org; s=100003; t=1739122079; bh=ynyGsY/hOsAFofCf+WN2352Doz/A4geySaubdzdYYuE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Xm/4vYbYEBRpX1ehyun0O7dIpwVrts/ZwoFCkxB0E7TPg4JCU34e/oVmRNyU/qvpG /9t9GimM6pUTZHgkyNoTCk2TtJS0ErPkN1ZjEVs7QWjKdyokmSh/eSkNmf19al3isy WL47WOnqO/C4x9HkFZrjPz4IiJxrQQuMiiPU2F3t+0xj3tfIsQKktUxnZebwL4879k BdgUKT8jgiyVFrP5pgjcop7mnGSqvrNDO9T3ub6wjIBnnf25Mq+rCv7KUpiB3qZiPH OrXQjZ82Rfyp/dTYIS66l3a25wzB9KkGRIYmLMp/0DuH5xwOiFGpgBBLgUDdgvqWvX KcVOS/O7+vGDA== From: Michael Clark To: qemu-devel@nongnu.org, Richard Henderson , Eduardo Habkost , Paolo Bonzini , Zhao Liu Cc: Michael Clark Subject: [PATCH v2 4/4] x86-disas: add x86-mini disassembler implementation Date: Mon, 10 Feb 2025 06:26:56 +1300 Message-ID: <20250209172656.1466556-5-michael@anarch128.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250209172656.1466556-1-michael@anarch128.org> References: <20250209172656.1466556-1-michael@anarch128.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2001:4801:7825:104:be76:4eff:fe10:52ae; envelope-from=michael@anarch128.org; helo=anarch128.org X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, DKIM_INVALID=0.1, DKIM_SIGNED=0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1739122168128019100 Content-Type: text/plain; charset="utf-8" the x86-mini library is a lightweight x86 encoder, decoder, and disassembler that uses extensions to the Intel instruction set metadata to encode modern VEX/EVEX instructions and legacy instructions with a parameterized LEX (legacy extension) format. this patch adds the x86-tablegen.py script, the disassembler, a print_insn_x86 implementation plus host and target cpu stubs. Signed-off-by: Michael Clark --- disas/disas-host.c | 5 + disas/meson.build | 97 ++ disas/x86-core.c | 3059 +++++++++++++++++++++++++++++++++++++++ disas/x86-disas.c | 94 ++ disas/x86.h | 1858 ++++++++++++++++++++++++ include/disas/dis-asm.h | 1 + target/i386/cpu.c | 7 + 7 files changed, 5121 insertions(+) create mode 100644 disas/x86-core.c create mode 100644 disas/x86-disas.c create mode 100644 disas/x86.h diff --git a/disas/disas-host.c b/disas/disas-host.c index 8146fafe804c..e2d171464a87 100644 --- a/disas/disas-host.c +++ b/disas/disas-host.c @@ -6,6 +6,7 @@ #include "qemu/osdep.h" #include "disas/disas.h" #include "disas/capstone.h" +#include "disas/x86.h" #include "disas-internal.h" =20 =20 @@ -50,12 +51,16 @@ static void initialize_debug_host(CPUDebug *s) s->info.cap_mode =3D CS_MODE_32; s->info.cap_insn_unit =3D 1; s->info.cap_insn_split =3D 8; + s->info.private_data =3D x86_ctx_create(x86_modes_32); + s->info.print_insn =3D print_insn_x86; #elif defined(__x86_64__) s->info.mach =3D bfd_mach_x86_64; s->info.cap_arch =3D CS_ARCH_X86; s->info.cap_mode =3D CS_MODE_64; s->info.cap_insn_unit =3D 1; s->info.cap_insn_split =3D 8; + s->info.private_data =3D x86_ctx_create(x86_modes_64); + s->info.print_insn =3D print_insn_x86; #elif defined(_ARCH_PPC) s->info.cap_arch =3D CS_ARCH_PPC; # ifdef _ARCH_PPC64 diff --git a/disas/meson.build b/disas/meson.build index bbfa11978352..dca926a00987 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -9,6 +9,103 @@ common_ss.add(when: 'CONFIG_RISCV_DIS', if_true: files( 'riscv-xthead.c', 'riscv-xventana.c' )) +x86_data =3D files( + 'x86-data/x86_adx.csv', + 'x86-data/x86_aes.csv', + 'x86-data/x86_aeskle.csv', + 'x86-data/x86_aesklewide.csv', + 'x86-data/x86_avx2.csv', + 'x86-data/x86_avx5124fmaps.csv', + 'x86-data/x86_avx5124vnniw.csv', + 'x86-data/x86_avx512b.csv', + 'x86-data/x86_avx512bf16.csv', + 'x86-data/x86_avx512bitalg.csv', + 'x86-data/x86_avx512bw.csv', + 'x86-data/x86_avx512cd.csv', + 'x86-data/x86_avx512d.csv', + 'x86-data/x86_avx512dq.csv', + 'x86-data/x86_avx512er.csv', + 'x86-data/x86_avx512f.csv', + 'x86-data/x86_avx512fp16.csv', + 'x86-data/x86_avx512ifma.csv', + 'x86-data/x86_avx512pf.csv', + 'x86-data/x86_avx512vbmi2.csv', + 'x86-data/x86_avx512vbmi.csv', + 'x86-data/x86_avx512vl.csv', + 'x86-data/x86_avx512vnni.csv', + 'x86-data/x86_avx512vp2intersect.csv', + 'x86-data/x86_avx512vpopcntdq.csv', + 'x86-data/x86_avx.csv', + 'x86-data/x86_avxneconvert.csv', + 'x86-data/x86_avxvnni.csv', + 'x86-data/x86_avxvnniint8.csv', + 'x86-data/x86_base.csv', + 'x86-data/x86_bmi1.csv', + 'x86-data/x86_bmi2.csv', + 'x86-data/x86_cet.csv', + 'x86-data/x86_cldemote.csv', + 'x86-data/x86_clwb.csv', + 'x86-data/x86_enqcmd.csv', + 'x86-data/x86_f16c.csv', + 'x86-data/x86_fma.csv', + 'x86-data/x86_fsgsbase.csv', + 'x86-data/x86_gfni.csv', + 'x86-data/x86_hreset.csv', + 'x86-data/x86_invpcid.csv', + 'x86-data/x86_lzcnt.csv', + 'x86-data/x86_mmx.csv', + 'x86-data/x86_movdir64b.csv', + 'x86-data/x86_movdiri.csv', + 'x86-data/x86_mpx.csv', + 'x86-data/x86_msrlist.csv', + 'x86-data/x86_ospke.csv', + 'x86-data/x86_pclmulqdq.csv', + 'x86-data/x86_pconfig.csv', + 'x86-data/x86_prefetchw.csv', + 'x86-data/x86_raoint.csv', + 'x86-data/x86_rdpid.csv', + 'x86-data/x86_rdrand.csv', + 'x86-data/x86_rdseed.csv', + 'x86-data/x86_rtm.csv', + 'x86-data/x86_serialize.csv', + 'x86-data/x86_sha.csv', + 'x86-data/x86_smap.csv', + 'x86-data/x86_sse2.csv', + 'x86-data/x86_sse3.csv', + 'x86-data/x86_sse4_1.csv', + 'x86-data/x86_sse4_2.csv', + 'x86-data/x86_sse4_3.csv', + 'x86-data/x86_sse.csv', + 'x86-data/x86_ssse3.csv', + 'x86-data/x86_uintr.csv', + 'x86-data/x86_vaes.csv', + 'x86-data/x86_vmx.csv', + 'x86-data/x86_waitpkg.csv', + 'x86-data/x86_wbnoinvd.csv', + 'x86-data/x86_x87.csv', + 'x86-data/x86_xsaveopt.csv' +) +x86_tablegen_py =3D find_program('../scripts/x86-tablegen.py') +x86_gen_enums_inc =3D custom_target( + 'x86-enums.inc', + output: 'x86-enums.inc', + depend_files: x86_data, + command: [x86_tablegen_py, '--print-opcode-enums', + '--output-file', '@OUTPUT@', x86_data] +) +x86_gen_tables_inc =3D custom_target( + 'x86-tables.inc', + output: 'x86-tables.inc', + depend_files: x86_data, + command: [x86_tablegen_py, '--print-opcode-tables', + '--output-file', '@OUTPUT@', x86_data] +) +common_ss.add(when: 'CONFIG_I386_DIS', if_true: x86_gen_enums_inc) +common_ss.add(when: 'CONFIG_I386_DIS', if_true: x86_gen_tables_inc) +common_ss.add(when: 'CONFIG_I386_DIS', if_true: files( + 'x86-core.c', + 'x86-disas.c' +)) common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c')) common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c')) common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.c')) diff --git a/disas/x86-core.c b/disas/x86-core.c new file mode 100644 index 000000000000..71833d7ec557 --- /dev/null +++ b/disas/x86-core.c @@ -0,0 +1,3059 @@ +/* + * Copyright (c) 2024-2025 Michael Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software= "), + * to deal in the Software without restriction, including without limitati= on + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL= ITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "qemu/osdep.h" +#include "qemu/host-utils.h" + +#include "disas/x86.h" +#include "disas/x86-tables.inc" + +#define array_size(arr) (sizeof(arr) / sizeof(arr[0])) + +typedef struct x86_table_col x86_table_col; +typedef struct x86_map_str x86_map_str; +typedef struct x86_operands x86_operands; +typedef struct x86_arg x86_arg; +typedef struct x86_opc_prefix x86_opc_prefix; +typedef struct x86_opr_formatter x86_opr_formatter; +typedef struct x86_opr_formats x86_opr_formats; + +typedef size_t (*x86_opr_str_fn)(char *buf, size_t buflen, x86_codec *c, + x86_arg a); +typedef size_t (*x86_opr_addr_fn)(char *buf, size_t buflen, x86_codec *c, + x86_arg a, size_t pc_offset, x86_fmt_symbol sym_cb); + +enum +{ + x86_state_top, + x86_state_segment, + x86_state_legacy, + x86_state_map_0f, + x86_state_lex_opcode, + x86_state_rex_opcode, + x86_state_vex_opcode, + x86_state_done, +}; + +struct x86_table_col +{ + int width; + char *data; +}; + +struct x86_map_str +{ + uint ord; + const char *str; +}; + +struct x86_opr_formatter +{ + x86_opr_str_fn fmt_const; + x86_opr_str_fn fmt_imm; + x86_opr_str_fn fmt_reg; + x86_opr_str_fn fmt_mrm; + x86_opr_str_fn fmt_vec; + x86_opr_str_fn fmt_opb; + x86_opr_str_fn fmt_is4; + x86_opr_str_fn fmt_ime; + x86_opr_addr_fn fmt_rel; +}; + +struct x86_opr_formats +{ + const char *ptr_rip; + const char *ptr_rip_disp; + const char *ptr_reg; + const char *ptr_reg_disp; + const char *ptr_reg_sreg; + const char *ptr_reg_sreg_disp; + const char *ptr_reg_reg; + const char *ptr_reg_reg_disp; + const char *ptr_sreg; + const char *ptr_disp; + const char *ptr_imm64; + const char *ptr_imm32; + const char *imm64; + const char *imm32; + const char *reg; +}; + +struct x86_operands +{ + ullong mod : 3; + ullong rm : 3; + ullong r : 5; + ullong x : 5; + ullong b : 5; + ullong s : 2; + ullong v : 5; + ullong k : 5; + ullong l : 2; + ullong w : 1; + ullong brd : 1; + ullong osz : 1; +}; + +struct x86_arg +{ + uint enc; + uint opr; + uint ord; + x86_operands q; +}; + +struct x86_opc_prefix +{ + uint pfx; + uint pfx_w; + uint pfx_o; + uint modfun; + uint modreg; + uint modmem; +}; + +x86_opr_formatter x86_format_intel_hex; +x86_opr_formatter x86_format_intel_dec; +x86_opr_formats x86_opr_formats_intel_hex; +x86_opr_formats x86_opr_formats_intel_dec; + +static uint debug; + +void x86_set_debug(uint d) { debug =3D d; } + +x86_map_str x86_mode_names[] =3D +{ + { x86_modes_64, "64" }, + { x86_modes_32, "32" }, + { x86_modes_16, "16" }, +}; + +x86_map_str x86_map_names[] =3D +{ + { x86_map_map6, "map6" }, + { x86_map_map5, "map5" }, + { x86_map_map4, "map4" }, + { x86_map_0f3a, "0f3a" }, + { x86_map_0f38, "0f38" }, + { x86_map_0f, "0f" }, +}; + +x86_map_str x86_ord_names[] =3D +{ + { x86_ord_rflags, "rflags" }, + { x86_ord_mxcsr, "mxcsr" }, + { x86_ord_xmm0_7, "xmm0_7" }, + { x86_ord_xmm0, "xmm0" }, + { x86_ord_seg, "seg" }, + { x86_ord_stx, "stx" }, + { x86_ord_st0, "st0" }, + { x86_ord_rdi, "rdi" }, + { x86_ord_rsi, "rsi" }, + { x86_ord_rbp, "rbp" }, + { x86_ord_rsp, "rsp" }, + { x86_ord_rbx, "rbx" }, + { x86_ord_rdx, "rdx" }, + { x86_ord_rcx, "rcx" }, + { x86_ord_rax, "rax" }, + { x86_ord_one, "one" }, + { x86_ord_ime, "ime" }, + { x86_ord_is4, "is4" }, + { x86_ord_sib, "sib" }, + { x86_ord_vec, "vec" }, + { x86_ord_opr, "opr" }, + { x86_ord_mrm, "mrm" }, + { x86_ord_reg, "reg" }, + { x86_ord_imm, "imm" }, + { x86_ord_rwi, "rwi" }, + { x86_ord_wi, "wi" }, + { x86_ord_ri, "ri" }, + { x86_ord_rw, "rw" }, + { x86_ord_i, "i" }, + { x86_ord_r, "r" }, + { x86_ord_w, "w" }, + { 0, NULL }, +}; + +x86_map_str x86_opr_names[] =3D +{ + { x86_opr_bnd_mem, "bnd/mem" }, + { x86_opr_k_m64, "k/m64" }, + { x86_opr_k_m32, "k/m32" }, + { x86_opr_k_m16, "k/m16" }, + { x86_opr_k_m8, "k/m8" }, + { x86_opr_vm64z, "vm64z" }, + { x86_opr_vm64y, "vm64y" }, + { x86_opr_vm64x, "vm64x" }, + { x86_opr_vm32z, "vm32z" }, + { x86_opr_vm32y, "vm32y" }, + { x86_opr_vm32x, "vm32x" }, + { x86_opr_rw_mw, "rw/mw" }, + { x86_opr_r64_m64, "r64/m64" }, + { x86_opr_r64_m32, "r64/m32" }, + { x86_opr_r64_m16, "r64/m16" }, + { x86_opr_r64_m8, "r64/m8" }, + { x86_opr_r32_m32, "r32/m32" }, + { x86_opr_r32_m16, "r32/m16" }, + { x86_opr_r32_m8, "r32/m8" }, + { x86_opr_r16_m16, "r16/m16" }, + { x86_opr_r16_m8, "r16/m8" }, + { x86_opr_r8_m8, "r8/m8" }, + { x86_opr_zmm_m512_m64bcst, "zmm/m512/m64bcst" }, + { x86_opr_zmm_m512_m32bcst, "zmm/m512/m32bcst" }, + { x86_opr_zmm_m512_m16bcst, "zmm/m512/m16bcst" }, + { x86_opr_ymm_m256_m64bcst, "ymm/m256/m64bcst" }, + { x86_opr_ymm_m256_m32bcst, "ymm/m256/m32bcst" }, + { x86_opr_ymm_m256_m16bcst, "ymm/m256/m16bcst" }, + { x86_opr_xmm_m128_m64bcst, "xmm/m128/m64bcst" }, + { x86_opr_xmm_m128_m32bcst, "xmm/m128/m32bcst" }, + { x86_opr_xmm_m128_m16bcst, "xmm/m128/m16bcst" }, + { x86_opr_xmm_m64_m32bcst, "xmm/m64/m32bcst" }, + { x86_opr_xmm_m64_m16bcst, "xmm/m64/m16bcst" }, + { x86_opr_xmm_m32_m16bcst, "xmm/m32/m16bcst" }, + { x86_opr_zmm_m512, "zmm/m512" }, + { x86_opr_ymm_m256, "ymm/m256" }, + { x86_opr_xmm_m128, "xmm/m128" }, + { x86_opr_xmm_m64, "xmm/m64" }, + { x86_opr_xmm_m32, "xmm/m32" }, + { x86_opr_xmm_m16, "xmm/m16" }, + { x86_opr_xmm_m8, "xmm/m8" }, + { x86_opr_mm_m64, "mm/m64" }, + { x86_opr_mm_m32, "mm/m32" }, + { x86_opr_mp, "mp" }, + { x86_opr_mw, "mw" }, + { x86_opr_vm64, "vm64" }, + { x86_opr_vm32, "vm32" }, + { x86_opr_r_m64, "r/m64" }, + { x86_opr_r_m32, "r/m32" }, + { x86_opr_r_m16, "r/m16" }, + { x86_opr_r_m8, "r/m8" }, + { x86_opr_m64bcst, "m64bcst" }, + { x86_opr_m32bcst, "m32bcst" }, + { x86_opr_m16bcst, "m16bcst" }, + { x86_opr_mib, "mib" }, + { x86_opr_m384, "m384" }, + { x86_opr_m80, "m80" }, + { x86_opr_m512, "m512" }, + { x86_opr_m256, "m256" }, + { x86_opr_m128, "m128" }, + { x86_opr_m64, "m64" }, + { x86_opr_m32, "m32" }, + { x86_opr_m16, "m16" }, + { x86_opr_m8, "m8" }, + { x86_opr_seg_gs, "gs" }, + { x86_opr_seg_fs, "fs" }, + { x86_opr_seg_ds, "ds" }, + { x86_opr_seg_ss, "ss" }, + { x86_opr_seg_cs, "cs" }, + { x86_opr_seg_es, "es" }, + { x86_opr_reg_xmm0_7, "xmm0_7" }, + { x86_opr_reg_xmm0, "xmm0" }, + { x86_opr_reg_pdi, "pdi" }, + { x86_opr_reg_psi, "psi" }, + { x86_opr_reg_pb, "pb" }, + { x86_opr_reg_pd, "pd" }, + { x86_opr_reg_pc, "pc" }, + { x86_opr_reg_pa, "pa" }, + { x86_opr_reg_bw, "bw" }, + { x86_opr_reg_dw, "dw" }, + { x86_opr_reg_cw, "cw" }, + { x86_opr_reg_aw, "aw" }, + { x86_opr_reg_rbx, "rbx" }, + { x86_opr_reg_rdx, "rdx" }, + { x86_opr_reg_rcx, "rcx" }, + { x86_opr_reg_rax, "rax" }, + { x86_opr_reg_ebx, "ebx" }, + { x86_opr_reg_edx, "edx" }, + { x86_opr_reg_ecx, "ecx" }, + { x86_opr_reg_eax, "eax" }, + { x86_opr_reg_bx, "bx" }, + { x86_opr_reg_dx, "dx" }, + { x86_opr_reg_cx, "cx" }, + { x86_opr_reg_ax, "ax" }, + { x86_opr_reg_cl, "cl" }, + { x86_opr_reg_al, "al" }, + { x86_opr_reg_st0, "st0" }, + { x86_opr_reg_v0, "v0" }, + { x86_opr_reg_ah, "ah" }, + { x86_opr_reg_di, "di" }, + { x86_opr_reg_si, "si" }, + { x86_opr_reg_d, "d" }, + { x86_opr_reg_c, "c" }, + { x86_opr_reg_a, "a" }, + { x86_opr_memfar16_64, "memfar16:64" }, + { x86_opr_memfar16_32, "memfar16:32" }, + { x86_opr_memfar16_16, "memfar16:16" }, + { x86_opr_far16_32, "far16:32" }, + { x86_opr_far16_16, "far16:16" }, + { x86_opr_relw, "relw" }, + { x86_opr_rel8, "rel8" }, + { x86_opr_moffs, "moffs" }, + { x86_opr_1, "1" }, + { x86_opr_zmm, "zmm" }, + { x86_opr_ymm, "ymm" }, + { x86_opr_xmm, "xmm" }, + { x86_opr_mm, "mm" }, + { x86_opr_ra, "ra" }, + { x86_opr_rw, "rw" }, + { x86_opr_r64, "r64" }, + { x86_opr_r32, "r32" }, + { x86_opr_r16, "r16" }, + { x86_opr_r8, "r8" }, + { x86_opr_iw, "iw" }, + { x86_opr_iwd, "iwd" }, + { x86_opr_i64, "i64" }, + { x86_opr_i32, "i32" }, + { x86_opr_i16, "i16" }, + { x86_opr_ib, "ib" }, + { x86_opr_bnd, "bnd" }, + { x86_opr_dreg, "dreg" }, + { x86_opr_creg, "creg" }, + { x86_opr_seg, "seg" }, + { x86_opr_k, "k" }, + { x86_opr_st, "st" }, + { x86_opr_mmx, "mmx" }, + { x86_opr_vec, "vec" }, + { x86_opr_reg, "reg" }, + { x86_opr_imm, "imm" }, + { x86_opr_bcst, "bcst" }, + { x86_opr_mem, "mem" }, + { x86_opr_flag_er, "{er}" }, + { x86_opr_flag_k, "{k}" }, + { x86_opr_flag_sae, "{sae}" }, + { x86_opr_flag_z, "{z}" }, + { x86_opr_flag_rs2, "{rs2}" }, + { x86_opr_flag_rs4, "{rs4}" }, + { x86_opr_f64x8, "/f64x8" }, + { x86_opr_f64x4, "/f64x4" }, + { x86_opr_f64x2, "/f64x2" }, + { x86_opr_f64x1, "/f64x1" }, + { x86_opr_f32x16, "/f32x16" }, + { x86_opr_f32x8, "/f32x8" }, + { x86_opr_f32x4, "/f32x4" }, + { x86_opr_f32x2, "/f32x2" }, + { x86_opr_f32x1, "/f32x1" }, + { x86_opr_f16x32, "/f16x32" }, + { x86_opr_f16x16, "/f16x16" }, + { x86_opr_f16x8, "/f16x8" }, + { x86_opr_f16x4, "/f16x4" }, + { x86_opr_f16x2, "/f16x2" }, + { x86_opr_f16x1, "/f16x1" }, + { x86_opr_f8x64, "/f8x64" }, + { x86_opr_f8x32, "/f8x32" }, + { x86_opr_f8x16, "/f8x16" }, + { x86_opr_f8x8, "/f8x8" }, + { x86_opr_f8x4, "/f8x4" }, + { x86_opr_f8x2, "/f8x2" }, + { x86_opr_f8x1, "/f8x1" }, + { x86_opr_i512x1, "/i512x1" }, + { x86_opr_i256x2, "/i256x2" }, + { x86_opr_i256x1, "/i256x1" }, + { x86_opr_i128x4, "/i128x4" }, + { x86_opr_i128x2, "/i128x2" }, + { x86_opr_i128x1, "/i128x1" }, + { x86_opr_i64x8, "/i64x8" }, + { x86_opr_i64x4, "/i64x4" }, + { x86_opr_i64x2, "/i64x2" }, + { x86_opr_i64x1, "/i64x1" }, + { x86_opr_i32x16, "/i32x16" }, + { x86_opr_i32x8, "/i32x8" }, + { x86_opr_i32x4, "/i32x4" }, + { x86_opr_i32x2, "/i32x2" }, + { x86_opr_i32x1, "/i32x1" }, + { x86_opr_i16x32, "/i16x32" }, + { x86_opr_i16x16, "/i16x16" }, + { x86_opr_i16x8, "/i16x8" }, + { x86_opr_i16x4, "/i16x4" }, + { x86_opr_i16x2, "/i16x2" }, + { x86_opr_i16x1, "/i16x1" }, + { x86_opr_i8x64, "/i8x64" }, + { x86_opr_i8x32, "/i8x32" }, + { x86_opr_i8x16, "/i8x16" }, + { x86_opr_i8x8, "/i8x8" }, + { x86_opr_i8x4, "/i8x4" }, + { x86_opr_i8x2, "/i8x2" }, + { x86_opr_i8x1, "/i8x1" }, + { 0, NULL }, +}; + +x86_map_str x86_enc_names[] =3D +{ + { x86_enc_r_norexb, " .norexb" }, + { x86_enc_r_lock, " .lock" }, + { x86_enc_r_rep, " .rep" }, + { x86_enc_s_a64, " .a64" }, + { x86_enc_s_a32, " .a32" }, + { x86_enc_s_a16, " .a16" }, + { x86_enc_s_o64, " .o64" }, + { x86_enc_s_o32, " .o32" }, + { x86_enc_s_o16, " .o16" }, + { x86_enc_j_i16, " i16" }, + { x86_enc_j_ib, " ib" }, + { x86_enc_i_i64, " i64" }, + { x86_enc_i_i32, " i32" }, + { x86_enc_i_i16, " i16" }, + { x86_enc_i_iwd, " iwd" }, + { x86_enc_i_iw, " iw" }, + { x86_enc_i_ib, " ib" }, + { x86_enc_f_opcode_r, "" }, + { x86_enc_f_opcode, "" }, + { x86_enc_f_modrm_n, "" }, + { x86_enc_f_modrm_r, "" }, + { x86_enc_o_opcode_r, "" }, + { x86_enc_t_evex, ".evex" }, + { x86_enc_t_vex, ".vex" }, + { x86_enc_t_lex, ".lex" }, + { x86_enc_l_lig, ".lig" }, + { x86_enc_l_512, ".512" }, + { x86_enc_l_256, ".256" }, + { x86_enc_l_128, ".128" }, + { x86_enc_l_l1, ".l1" }, + { x86_enc_l_l0, ".l0" }, + { x86_enc_l_lz, ".lz" }, + { x86_enc_p_rexw, ".w" }, + { x86_enc_p_9b, ".9b" }, + { x86_enc_p_f2, ".f2" }, + { x86_enc_p_f3, ".f3" }, + { x86_enc_p_66, ".66" }, + { x86_enc_m_map6, ".map6" }, + { x86_enc_m_map5, ".map5" }, + { x86_enc_m_map4, ".map4" }, + { x86_enc_m_0f3a, ".0f3a" }, + { x86_enc_m_0f38, ".0f38" }, + { x86_enc_m_0f, ".0f" }, + { x86_enc_w_wig, ".wig" }, + { x86_enc_w_ww, ".ww" }, + { x86_enc_w_wx, ".wx" }, + { x86_enc_w_wn, ".wn" }, + { x86_enc_w_wb, ".wb" }, + { x86_enc_w_w1, ".w1" }, + { x86_enc_w_w0, ".w0" }, + { 0, NULL }, +}; + +/* + * string tables + */ + +static size_t x86_name_map(x86_map_str *p, char * buf, size_t len, uint or= d, + const char *sep) +{ + size_t count =3D 0; + int ret =3D 0; + for (;;) { + while (p->str !=3D NULL) { + if (p->ord && (p->ord & ord) =3D=3D p->ord) { + ord =3D ord & ~p->ord; + break; + } + p++; + } + if (p->str =3D=3D NULL) break; + if (buf =3D=3D NULL || len - count <=3D len) { + ret =3D snprintf(buf ? buf + count : NULL, + buf ? len - count : 0, + "%s%s", count =3D=3D 0 ? "" : sep, p->str); + if (ret > 0) count +=3D ret; + } + } + return count; +} + +size_t x86_mode_name(char *buf, size_t len, uint mode, const char *sep) +{ + return x86_name_map(x86_mode_names, buf, len, mode, sep); +} + +size_t x86_map_name(char *buf, size_t len, uint mode, const char *sep) +{ + return x86_name_map(x86_map_names, buf, len, mode, sep); +} + +size_t x86_ord_name(char *buf, size_t len, uint ord, const char *sep) +{ + return x86_name_map(x86_ord_names, buf, len, ord, sep); +} + +size_t x86_opr_name(char *buf, size_t len, uint opr) +{ + return x86_name_map(x86_opr_names, buf, len, opr, ""); +} + +size_t x86_enc_name(char *buf, size_t len, uint enc) +{ + return x86_name_map(x86_enc_names, buf, len, enc, ""); +} + +const char *x86_reg_name(uint reg) +{ + return (reg < 512) ? x86_reg_names[reg] : "invalid"; +} + +size_t x86_ord_mnem(char *buf, size_t len, const ushort *ord) +{ + const char codes[8] =3D " -irmvo "; + size_t count =3D 0; + for (size_t i =3D 0; i < array_size(x86_ord_table[0].ord) && ord[i]; i= ++) { + uint type =3D x86_ord_type_val(ord[i]); + if (buf && count < len) { + buf[count++] =3D codes[type]; + } + } + buf[count] =3D '\0'; + return count; +} + +const char *x86_table_type_name(uint type) +{ + switch (type) { + case x86_table_none: return "none"; + case x86_table_lex: return "lex"; + case x86_table_vex: return "vex"; + case x86_table_evex: return "evex"; + default: return ""; + } +} + +const char *x86_table_map_name(uint map) +{ + switch (map) { + case x86_map_none: return ""; + case x86_map_0f: return "0f"; + case x86_map_0f38: return "0f38"; + case x86_map_0f3a: return "0f3a"; + case x86_map_map4: return "map4"; + case x86_map_map5: return "map5"; + case x86_map_map6: return "map6"; + default: return ""; + } +} + +const char *x86_table_prefix_name(uint prefix) +{ + switch (prefix) { + case x86_pfx_66: return "66"; + case x86_pfx_f3: return "f3"; + case x86_pfx_f2: return "f2"; + case x86_pfx_9b: return "9b"; + case x86_pfx_66 | x86_pfx_rexw: return "66+w"; + case x86_pfx_f3 | x86_pfx_rexw: return "f3+w"; + case x86_pfx_f2 | x86_pfx_rexw: return "f2+w"; + case x86_pfx_9b | x86_pfx_rexw: return "9b+w"; + default: return ""; + } +} + +/* + * string formatting + */ + +static const char dd[200] =3D { + 0x30, 0x30, 0x30, 0x31, 0x30, 0x32, 0x30, 0x33, 0x30, 0x34, + 0x30, 0x35, 0x30, 0x36, 0x30, 0x37, 0x30, 0x38, 0x30, 0x39, + 0x31, 0x30, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, 0x31, 0x34, + 0x31, 0x35, 0x31, 0x36, 0x31, 0x37, 0x31, 0x38, 0x31, 0x39, + 0x32, 0x30, 0x32, 0x31, 0x32, 0x32, 0x32, 0x33, 0x32, 0x34, + 0x32, 0x35, 0x32, 0x36, 0x32, 0x37, 0x32, 0x38, 0x32, 0x39, + 0x33, 0x30, 0x33, 0x31, 0x33, 0x32, 0x33, 0x33, 0x33, 0x34, + 0x33, 0x35, 0x33, 0x36, 0x33, 0x37, 0x33, 0x38, 0x33, 0x39, + 0x34, 0x30, 0x34, 0x31, 0x34, 0x32, 0x34, 0x33, 0x34, 0x34, + 0x34, 0x35, 0x34, 0x36, 0x34, 0x37, 0x34, 0x38, 0x34, 0x39, + 0x35, 0x30, 0x35, 0x31, 0x35, 0x32, 0x35, 0x33, 0x35, 0x34, + 0x35, 0x35, 0x35, 0x36, 0x35, 0x37, 0x35, 0x38, 0x35, 0x39, + 0x36, 0x30, 0x36, 0x31, 0x36, 0x32, 0x36, 0x33, 0x36, 0x34, + 0x36, 0x35, 0x36, 0x36, 0x36, 0x37, 0x36, 0x38, 0x36, 0x39, + 0x37, 0x30, 0x37, 0x31, 0x37, 0x32, 0x37, 0x33, 0x37, 0x34, + 0x37, 0x35, 0x37, 0x36, 0x37, 0x37, 0x37, 0x38, 0x37, 0x39, + 0x38, 0x30, 0x38, 0x31, 0x38, 0x32, 0x38, 0x33, 0x38, 0x34, + 0x38, 0x35, 0x38, 0x36, 0x38, 0x37, 0x38, 0x38, 0x38, 0x39, + 0x39, 0x30, 0x39, 0x31, 0x39, 0x32, 0x39, 0x33, 0x39, 0x34, + 0x39, 0x35, 0x39, 0x36, 0x39, 0x37, 0x39, 0x38, 0x39, 0x39 +}; + +static inline size_t utoa_u32(uint n, char *s) +{ + const uchar utodb_u32[32] =3D { + 9, 9, 9, 8, 8, 8, 7, 7, + 7, 6, 6, 6, 6, 5, 5, 5, + 4, 4, 4, 3, 3, 3, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, + }; + const uint utodd_u32[10] =3D { + 999999999u, 99999999u, + 9999999u, 999999u, + 99999u, 9999u, + 999u, 99u, + 9u, 0u, + }; + uint x1, x2, a1, a2, a3, b1, b2; + uint dig =3D n =3D=3D 0 ? 1 : utodb_u32[clz32(n)]; + dig +=3D n > utodd_u32[9 - dig]; + x1 =3D n % 1000000; x2 =3D n / 1000000; + switch (dig) { + case 9: + b2 =3D x2 / 100 % 100; + *s++ =3D dd[b2 * 2 + 1]; + goto l8; + case 7: + b1 =3D x2 % 100; + *s++ =3D dd[b1 * 2 + 1]; + goto l6; + case 5: + a3 =3D x1 / 10000; + *s++ =3D dd[a3 * 2 + 1]; + goto l4; + case 3: + a2 =3D x1 / 100 % 100; + *s++ =3D dd[a2 * 2 + 1]; + goto l2; + case 1: + a1 =3D x1 % 100; + *s++ =3D dd[a1 * 2 + 1]; + break; + case 10: + b2 =3D x2 / 100 % 100; + *s++ =3D dd[b2 * 2]; + *s++ =3D dd[b2 * 2 + 1]; + /* fallthrough */ + case 8: l8: + b1 =3D x2 % 100; + *s++ =3D dd[b1 * 2]; + *s++ =3D dd[b1 * 2 + 1]; + /* fallthrough */ + case 6: l6: + a3 =3D x1 / 10000; + *s++ =3D dd[a3 * 2]; + *s++ =3D dd[a3 * 2 + 1]; + /* fallthrough */ + case 4: l4: + a2 =3D x1 / 100 % 100; + *s++ =3D dd[a2 * 2]; + *s++ =3D dd[a2 * 2 + 1]; + /* fallthrough */ + case 2: l2: + a1 =3D x1 % 100; + *s++ =3D dd[a1 * 2]; + *s++ =3D dd[a1 * 2 + 1]; + break; + } + *s++ =3D '\0'; + return dig; +} + +static inline size_t utoa_u64(ullong n, char *s) +{ + const uchar utodb_u64[64] =3D { + 19, 18, 18, 18, 18, 17, 17, 17, + 16, 16, 16, 15, 15, 15, 15, 14, + 14, 14, 13, 13, 13, 12, 12, 12, + 12, 11, 11, 11, 10, 10, 10, 9, + 9, 9, 9, 8, 8, 8, 7, 7, + 7, 6, 6, 6, 6, 5, 5, 5, + 4, 4, 4, 3, 3, 3, 3, 2, + 2, 2, 1, 1, 1, 1, 1, 1, + }; + const ullong utodd_u64[20] =3D { + 9999999999999999999llu, 999999999999999999llu, + 99999999999999999llu, 9999999999999999llu, + 999999999999999llu, 99999999999999llu, + 9999999999999llu, 999999999999llu, + 99999999999llu, 9999999999llu, + 999999999llu, 99999999llu, + 9999999llu, 999999llu, + 99999llu, 9999llu, + 999llu, 99llu, + 9llu, 0llu, + }; + ullong x1, x2; + uint y1, y2, z1, z2, a1, a2, a3, b1, b2, b3, c1, c2, c3, d1; + uint dig =3D n =3D=3D 0 ? 1 : utodb_u64[clz64(n)]; + dig +=3D n > utodd_u64[19 - dig]; + x1 =3D n % 1000000000000ll; x2 =3D n / 1000000000000ll; + y1 =3D x1 % 1000000ll; y2 =3D x1 / 1000000ll; + z1 =3D x2 % 1000000ll; z2 =3D x2 / 1000000ll; + switch (dig) { + case 19: + d1 =3D z2 % 100; + *s++ =3D dd[d1 * 2 + 1]; + goto l18; + case 17: + c3 =3D z1 / 10000; + *s++ =3D dd[c3 * 2 + 1]; + goto l16; + case 15: + c2 =3D z1 / 100 % 100; + *s++ =3D dd[c2 * 2 + 1]; + goto l14; + case 13: + c1 =3D z1 % 100; + *s++ =3D dd[c1 * 2 + 1]; + goto l12; + case 11: + b3 =3D y2 / 10000; + *s++ =3D dd[b3 * 2 + 1]; + goto l10; + case 9: + b2 =3D y2 / 100 % 100; + *s++ =3D dd[b2 * 2 + 1]; + goto l8; + case 7: + b1 =3D y2 % 100; + *s++ =3D dd[b1 * 2 + 1]; + goto l6; + case 5: + a3 =3D y1 / 10000; + *s++ =3D dd[a3 * 2 + 1]; + goto l4; + case 3: + a2 =3D y1 / 100 % 100; + *s++ =3D dd[a2 * 2 + 1]; + goto l2; + case 1: + a1 =3D y1 % 100; + *s++ =3D dd[a1 * 2 + 1]; + break; + case 20: + d1 =3D z2 % 100; + *s++ =3D dd[d1 * 2]; + *s++ =3D dd[d1 * 2 + 1]; + /* fallthrough */ + case 18: l18: + c3 =3D z1 / 10000; + *s++ =3D dd[c3 * 2]; + *s++ =3D dd[c3 * 2 + 1]; + /* fallthrough */ + case 16: l16: + c2 =3D z1 / 100 % 100; + *s++ =3D dd[c2 * 2]; + *s++ =3D dd[c2 * 2 + 1]; + /* fallthrough */ + case 14: l14: + c1 =3D z1 % 100; + *s++ =3D dd[c1 * 2]; + *s++ =3D dd[c1 * 2 + 1]; + /* fallthrough */ + case 12: l12: + b3 =3D y2 / 10000; + *s++ =3D dd[b3 * 2]; + *s++ =3D dd[b3 * 2 + 1]; + /* fallthrough */ + case 10: l10: + b2 =3D y2 / 100 % 100; + *s++ =3D dd[b2 * 2]; + *s++ =3D dd[b2 * 2 + 1]; + /* fallthrough */ + case 8: l8: + b1 =3D y2 % 100; + *s++ =3D dd[b1 * 2]; + *s++ =3D dd[b1 * 2 + 1]; + /* fallthrough */ + case 6: l6: + a3 =3D y1 / 10000; + *s++ =3D dd[a3 * 2]; + *s++ =3D dd[a3 * 2 + 1]; + /* fallthrough */ + case 4: l4: + a2 =3D y1 / 100 % 100; + *s++ =3D dd[a2 * 2]; + *s++ =3D dd[a2 * 2 + 1]; + /* fallthrough */ + case 2: l2: + a1 =3D y1 % 100; + *s++ =3D dd[a1 * 2]; + *s++ =3D dd[a1 * 2 + 1]; + break; + } + *s++ =3D '\0'; + return dig; +} + +static const char *hexdigits =3D "0123456789abcdef"; + +static size_t xvappend_char(char *restrict out, size_t o, size_t n, char c) +{ + if (out && o < n) { + out[o] =3D c; + } + return o + 1; +} + +static size_t xvappend_hex_u32(char *restrict out, size_t o, size_t n, + uint val) +{ + size_t dig =3D (32 - clz32(val) + 3) / 4; + for (size_t i =3D dig - 1; i < dig; i--) { + o =3D xvappend_char(out, o, n, hexdigits[(val >> (i * 4)) & 0xf]); + } + return o; +} + +static size_t xvappend_hex_u64(char *restrict out, size_t o, size_t n, + ullong val) +{ + size_t dig =3D (64 - clz64(val) + 3) / 4; + for (size_t i =3D dig - 1; i < dig; i--) { + o =3D xvappend_char(out, o, n, hexdigits[(val >> (i * 4)) & 0xf]); + } + return o; +} + +static int xvsnprintf(char *restrict out, size_t n, const char* fmt, + va_list vl) +{ + int w =3D -1, s =3D 0, c; + size_t o =3D 0, l; + const char *v; + char t[21]; + for ( ; *fmt; fmt++) { + if (w >=3D 0) { + switch (*fmt) { + case 'l': + w =3D w < 2 ? w + 1 : w; + break; + case 'd': + s =3D 1; + /* fallthrough */ + case 'u': + if (w =3D=3D 0 || sizeof(long) =3D=3D 4) { + int val =3D va_arg(vl, int); + if (s && val < 0) { + val =3D -val; + o =3D xvappend_char(out, o, n, '-'); + } + l =3D utoa_u32(val, t); + } + else if (w =3D=3D 2 || sizeof(long) =3D=3D 8) { + llong val =3D va_arg(vl, llong); + if (s && val < 0) { + val =3D -val; + o =3D xvappend_char(out, o, n, '-'); + } + l =3D utoa_u64(val, t); + } + l =3D n - o < l ? n - o : l; + memcpy(out + o, t, l); + o +=3D l; + w =3D -1; + s =3D 0; + break; + case 'p': + o =3D xvappend_char(out, o, n, '0'); + o =3D xvappend_char(out, o, n, 'x'); + w =3D 2; + /* fallthrough */ + case 'x': + if (w =3D=3D 0 || sizeof(long) =3D=3D 4) { + int val =3D va_arg(vl, int); + o =3D xvappend_hex_u32(out, o, n, val); + } + else if (w =3D=3D 2 || sizeof(long) =3D=3D 8) { + llong val =3D va_arg(vl, llong); + o =3D xvappend_hex_u64(out, o, n, val); + } + w =3D -1; + break; + case 's': + v =3D va_arg(vl, const char *); + l =3D strlen(v); + memcpy(out + o, v, n - o < l ? n - o : l); + o +=3D l; + w =3D -1; + break; + case 'c': + c =3D va_arg(vl, int); + o =3D xvappend_char(out, o, n, (char)c); + w =3D -1; + break; + } + } + else if (*fmt =3D=3D '%') { + w =3D 0; + } + else { + o =3D xvappend_char(out, o, n, *fmt); + } + } + if (out) { + out[o < n ? o : n ? n - 1 : 0] =3D 0; + } + return o; +} + +static inline int xsnprintf(char *out, size_t n, const char *fmt, ...) +{ + va_list vl; + va_start(vl, fmt); + int res =3D xvsnprintf(out, n, fmt, vl); + va_end(vl); + return res; +} + +/* + * metadata filters + */ + +int x86_enc_filter_rex(x86_rex prefix, uint enc) +{ + uint lex =3D (enc & x86_enc_t_mask) =3D=3D x86_enc_t_lex; + uint ew0 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w0; + uint ew1 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w1; + uint ewn =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wn; + uint ewb =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wb; + uint eww =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_ww; + uint ewx =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wx; + uint ewig =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wig; + uint norexb =3D (enc & x86_enc_r_norexb) !=3D 0; + + uint w =3D (prefix.data[0] >> 3) & 1; + + if (!lex) return -1; + if (norexb) return -1; + + switch (w) { + case x86_vex_w0: + if (!(ew0 || ewig || ewn || ewb || eww || ewx)) return -1; + break; + case x86_vex_w1: + if (!(ew1 || ewig || ewn || ewb || eww || ewx)) return -1; + break; + } + + return 0; +} + +int x86_enc_filter_rex2(x86_rex2 prefix, uint enc) +{ + uint lex =3D (enc & x86_enc_t_mask) =3D=3D x86_enc_t_lex; + uint ew0 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w0; + uint ew1 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w1; + uint ewig =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wig; + uint em =3D (enc & x86_enc_m_mask) >> x86_enc_m_shift; + + uint m =3D (prefix.data[0] >> 7) & 1; + uint w =3D (prefix.data[0] >> 3) & 1; + + if (!lex || m !=3D em) return -1; + + switch (w) { + case x86_vex_w0: if (!(ew0 || ewig)) return -1; break; + case x86_vex_w1: if (!(ew1 || ewig)) return -1; break; + default: return -1; + } + + return 0; +} + +int x86_enc_filter_vex2(x86_vex2 prefix, uint enc) +{ + uint vex =3D (enc & x86_enc_t_mask) =3D=3D x86_enc_t_vex; + uint ew0 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w0; + uint ewig =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wig; + uint lz =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_lz; + uint l0 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_l0; + uint l1 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_l1; + uint l128 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_128; + uint l256 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_256; + uint lig =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_lig; + uint np =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_none; + uint p66 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_66; + uint pf2 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_f2; + uint pf3 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_f3; + uint em =3D (enc & x86_enc_m_mask) >> x86_enc_m_shift; + + uint p =3D (prefix.data[0] >> 0) & 3; + uint l =3D (prefix.data[0] >> 2) & 1; + + if (!vex || !(ew0 || ewig) || x86_map_0f !=3D em) return -1; + + switch (l) { + case x86_vex_l0: if (!(lig || lz || l0 || l128)) return -1; break; + case x86_vex_l1: if (!(lig || l1 || l256)) return -1; break; + default: return -1; + } + + switch (p) { + case x86_pfx_none: if (!np) return -1; break; + case x86_pfx_66: if (!p66) return -1; break; + case x86_pfx_f2: if (!pf2) return -1; break; + case x86_pfx_f3: if (!pf3) return -1; break; + default: return -1; + } + + return 0; +} + +int x86_enc_filter_vex3(x86_vex3 prefix, uint enc) +{ + uint vex =3D (enc & x86_enc_t_mask) =3D=3D x86_enc_t_vex; + uint ew0 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w0; + uint ew1 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w1; + uint ewig =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wig; + uint lz =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_lz; + uint l0 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_l0; + uint l1 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_l1; + uint l128 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_128; + uint l256 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_256; + uint lig =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_lig; + uint np =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_none; + uint p66 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_66; + uint pf2 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_f2; + uint pf3 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_f3; + uint em =3D (enc & x86_enc_m_mask) >> x86_enc_m_shift; + + uint m =3D (prefix.data[0] >> 0) & 31; + uint w =3D (prefix.data[1] >> 7) & 1; + uint p =3D (prefix.data[1] >> 0) & 3; + uint l =3D (prefix.data[1] >> 2) & 1; + + if (!vex || m !=3D em) return -1; + + switch (w) { + case x86_vex_w0: if (!(ew0 || ewig)) return -1; break; + case x86_vex_w1: if (!(ew1 || ewig)) return -1; break; + default: return -1; + } + + switch (l) { + case x86_vex_l0: if (!(lig || lz || l0 || l128)) return -1; break; + case x86_vex_l1: if (!(lig || l1 || l256)) return -1; break; + default: return -1; + } + + switch (p) { + case x86_pfx_none: if (!np) return -1; break; + case x86_pfx_66: if (!p66) return -1; break; + case x86_pfx_f2: if (!pf2) return -1; break; + case x86_pfx_f3: if (!pf3) return -1; break; + default: return -1; + } + + return 0; +} + +int x86_enc_filter_evex(x86_evex prefix, uint enc) +{ + uint evex =3D (enc & x86_enc_t_mask) =3D=3D x86_enc_t_evex; + uint ew0 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w0; + uint ew1 =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_w1; + uint ewig =3D (enc & x86_enc_w_mask) =3D=3D x86_enc_w_wig; + uint l128 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_128; + uint l256 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_256; + uint l512 =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_512; + uint lig =3D (enc & x86_enc_l_mask) =3D=3D x86_enc_l_lig; + uint np =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_none; + uint p66 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_66; + uint pf2 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_f2; + uint pf3 =3D (enc & x86_enc_p_mask) =3D=3D x86_enc_p_f3; + uint em =3D (enc & x86_enc_m_mask) >> x86_enc_m_shift; + + uint m =3D (prefix.data[0] >> 0) & 7; + uint w =3D (prefix.data[1] >> 7) & 1; + uint p =3D (prefix.data[1] >> 0) & 3; + uint l =3D (prefix.data[2] >> 5) & 3; + + if (!evex || m !=3D em) return -1; + + switch (w) { + case x86_vex_w0: if (!(ew0 || ewig)) return -1; break; + case x86_vex_w1: if (!(ew1 || ewig)) return -1; break; + default: return -1; + } + + switch (l) { + case x86_vex_l0: if (!(lig || l128)) return -1; break; + case x86_vex_l1: if (!(lig || l256)) return -1; break; + case x86_vex_l2: if (!(lig || l512)) return -1; break; + default: return -1; + } + + switch (p) { + case x86_pfx_none: if (!np) return -1; break; + case x86_pfx_66: if (!p66) return -1; break; + case x86_pfx_f2: if (!pf2) return -1; break; + case x86_pfx_f3: if (!pf3) return -1; break; + default: return -1; + } + + return 0; +} + +/* + * table sorting + */ + +static int x86_opc_data_compare_opcode(const void *p1, const void *p2) +{ + const x86_opc_data *op1 =3D x86_opc_table + *(size_t *)p1; + const x86_opc_data *op2 =3D x86_opc_table + *(size_t *)p2; + + /* split into prefix and suffix */ + uint mask =3D x86_enc_t_mask | x86_enc_p_mask | x86_enc_m_mask; + uint op1pre =3D op1->enc & mask; + uint op2pre =3D op2->enc & mask; + uint op1suf =3D op1->enc & ~mask; + uint op2suf =3D op2->enc & ~mask; + + if (op1pre < op2pre) return -1; + if (op1pre > op2pre) return 1; + if (op1->opc[0] < op2->opc[0]) return -1; + if (op1->opc[0] > op2->opc[0]) return 1; + if (op1->opc[1] < op2->opc[1]) return -1; + if (op1->opc[1] > op2->opc[1]) return 1; + if (op1suf < op2suf) return -1; + if (op1suf > op2suf) return 1; + return 0; +} + +static int x86_opc_data_compare_alpha(const void *p1, const void *p2) +{ + const x86_opc_data *op1 =3D x86_opc_table + *(size_t *)p1; + const x86_opc_data *op2 =3D x86_opc_table + *(size_t *)p2; + int alpha =3D strcmp(x86_op_names[op1->op], x86_op_names[op2->op]); + if (alpha =3D=3D 0) return x86_opc_data_compare_opcode(p1, p2); + else return alpha; +} + +static x86_table_idx x86_opc_table_index(size_t n) +{ + x86_table_idx tab =3D { n, g_malloc(sizeof(size_t) * n) }; + for (size_t i =3D 0; i < tab.count; i++) tab.idx[i] =3D i; + return tab; +} + +x86_table_idx x86_opc_table_identity(void) +{ + return x86_opc_table_index(x86_opc_table_size); +} + +x86_table_idx x86_opc_table_sorted(x86_table_idx tab, uint sort) +{ + switch (sort) { + case x86_sort_none: + break; + case x86_sort_numeric: + qsort(tab.idx, tab.count, sizeof(size_t), x86_opc_data_compare_opc= ode); + break; + case x86_sort_alpha: + qsort(tab.idx, tab.count, sizeof(size_t), x86_opc_data_compare_alp= ha); + break; + } + return tab; +} + +x86_table_idx x86_opc_table_filter(x86_table_idx tab, uint modes) +{ + size_t count =3D 0; + for (size_t i =3D 0; i < tab.count; i++) { + const x86_opc_data *d =3D x86_opc_table + tab.idx[i]; + if (d->mode & modes) count++; + } + x86_table_idx newtab =3D { count, g_malloc(sizeof(size_t) * count) }; + count =3D 0; + for (size_t i =3D 0; i < tab.count; i++) { + const x86_opc_data *d =3D x86_opc_table + tab.idx[i]; + if (d->mode & modes) newtab.idx[count++] =3D i; + } + g_free(tab.idx); + return newtab; +} + +static int x86_opc_data_compare_masked(const void *p1, const void *p2) +{ + x86_opc_data *om1 =3D (x86_opc_data *)p1; + x86_opc_data *om2 =3D (x86_opc_data *)p2; + uint enc1 =3D om1->enc, enc2 =3D om2->enc; + uint pre1 =3D enc1 & (x86_enc_t_mask | x86_enc_m_mask | x86_enc_prexw_= mask); + uint pre2 =3D enc2 & (x86_enc_t_mask | x86_enc_m_mask | x86_enc_prexw_= mask); + if (pre1 < pre2) return -1; + if (pre1 > pre2) return 1; + ushort mask_s =3D om1->opm_s & om2->opm_s; + if ((om1->opc_s & mask_s) < (om2->opc_s & mask_s)) return -1; + if ((om1->opc_s & mask_s) > (om2->opc_s & mask_s)) return 1; + /* suffix is unnecessary for matching opcodes because it contains form= at*/ + return 0; +} + +static int x86_opc_data_compare_build(const void *p1, const void *p2) +{ + x86_opc_data *om1 =3D (x86_opc_data *)p1; + x86_opc_data *om2 =3D (x86_opc_data *)p2; + uint enc1 =3D om1->enc, enc2 =3D om2->enc; + uint pre1 =3D enc1 & (x86_enc_t_mask | x86_enc_m_mask | x86_enc_prexw_= mask); + uint pre2 =3D enc2 & (x86_enc_t_mask | x86_enc_m_mask | x86_enc_prexw_= mask); + if (pre1 < pre2) return -1; + if (pre1 > pre2) return 1; + for (size_t i =3D 0; i < 2; i++) { + if (om1->opc[i] < om2->opc[i]) return -1; + if (om1->opc[i] > om2->opc[i]) return 1; + /* most specific mask first for fixed modrm */ + if (om1->opm[i] < om2->opm[i]) return 1; + if (om1->opm[i] > om2->opm[i]) return -1; + } + uint suf1 =3D enc1 & ~(x86_enc_t_mask | x86_enc_m_mask | x86_enc_prexw= _mask); + uint suf2 =3D enc2 & ~(x86_enc_t_mask | x86_enc_m_mask | x86_enc_prexw= _mask); + if (suf1 < suf2) return -1; + if (suf1 > suf2) return 1; + return 0; +} + +/* + * table construction + */ + +static x86_opc_prefix x86_table_make_prefix(const x86_opc_data *d, + const x86_opr_data *o, const x86_ord_data *p) +{ + x86_opc_prefix tp; + memset(&tp, 0, sizeof(tp)); + + /* extract prefix and synthesize width prefixes */ + switch (x86_enc_type(d->enc)) { + case x86_enc_t_lex: + case x86_enc_t_vex: + case x86_enc_t_evex: + switch (d->enc & x86_enc_w_mask) { + case x86_enc_w_wig: + case x86_enc_w_wn: + case x86_enc_w_wb: + case x86_enc_w_w0: break; + case x86_enc_w_w1: tp.pfx =3D x86_enc_p_rexw; break; + case x86_enc_w_wx: tp.pfx_w =3D x86_enc_p_rexw; /* fallthrough */ + case x86_enc_w_ww: tp.pfx_o =3D x86_enc_p_66; break; + } + break; + } + + /* find register or memory operand mapping to modrm.rm field + * so that we can add mod=3D0b11 or mod!=3D0b11 to modrm mask */ + tp.modfun =3D x86_enc_func(d->enc) =3D=3D x86_enc_f_modrm_n; + for (size_t i =3D 0; i < array_size(o->opr) && o->opr[i]; i++) { + uint isreg =3D x86_opr_type_val(o->opr[i]) >=3D x86_opr_reg; + uint ismem =3D x86_opr_has_mem(o->opr[i]); + uint ismrm =3D x86_ord_type_val(p->ord[i]) =3D=3D x86_ord_mrm; + if (ismrm) { + if (isreg && !ismem) { + tp.modreg =3D 1; /* mod =3D=3D 0b11 */ + break; + } else if (!isreg && ismem) { + tp.modmem =3D 1; /* mod !=3D 0b11 */ + break; + } + } + } + + /* explict second opcode byte has mod =3D=3D 0b11 */ + if (d->opm[1] =3D=3D 0xff && (d->opc[1] & 0xc0) =3D=3D 0xc0 && + !tp.modreg && !tp.modmem) + { + tp.modreg =3D 1; + } + + return tp; +} + +static void x86_build_prefix_clashes(x86_acc_idx *idx, x86_table_idx tab, + ullong *modfun, ullong *modmod) +{ + /* + * record modrm.reg /n or modrm.mod (reg or mem) usage + * so that opcodes with clashes can expand mod entries + */ + for (size_t i =3D 0; i < tab.count; i++) { + const x86_opc_data *d =3D x86_opc_table + tab.idx[i]; + const x86_opr_data *o =3D x86_opr_table + d->opr; + const x86_ord_data *p =3D x86_ord_table + d->ord; + x86_opc_prefix tp =3D x86_table_make_prefix(d, o, p); + uint type =3D x86_enc_type(d->enc) >> x86_enc_t_shift; + uint prefix =3D x86_enc_prefix(d->enc) >> x86_enc_p_shift; + uint map =3D x86_enc_map(d->enc) >> x86_enc_m_shift; + size_t tpm =3D x86_acc_page(type, prefix, map); + size_t x =3D (tpm << 8) | d->opc[0]; + if (tp.modfun) { + x86_bitmap_set(modfun, x, 1); + } + if (tp.modreg || tp.modmem) { + x86_bitmap_set(modmod, x, 1); + } + } +} + +static size_t x86_add_opc_data(x86_opc_data *op_map, size_t idx, + x86_opc_data rec, uint modreg, uint modmem, uint modcla) +{ + /* + * add entries to opcode map, expanding mod entries where + * for modreg or modmem constraints or clashes with mod.reg /n + */ + if (op_map) { + if (modreg) { + /* add one entry with mod =3D=3D 0b11 - ModRM.rm is register */ + rec.opm[1] |=3D 0xc0; + rec.opc[1] |=3D 0xc0; + op_map[idx] =3D rec; + } else if (modmem) { + /* add three entries with mod !=3D 0b11 - ModRM.rm is memory */ + rec.opm[1] |=3D 0xc0; + rec.opc[1] =3D (rec.opc[1] & 0x3f) | 0x80; + op_map[idx] =3D rec; + rec.opc[1] =3D (rec.opc[1] & 0x3f) | 0x40; + op_map[idx + 1] =3D rec; + rec.opc[1] =3D (rec.opc[1] & 0x3f); + op_map[idx + 2] =3D rec; + } else if (modcla) { + /* add four entries mod (0b00..0b11) due to function clash */ + rec.opm[1] |=3D 0xc0; + rec.opc[1] =3D (rec.opc[1] & 0x3f) | 0xc0; + op_map[idx] =3D rec; + rec.opc[1] =3D (rec.opc[1] & 0x3f) | 0x80; + op_map[idx + 1] =3D rec; + rec.opc[1] =3D (rec.opc[1] & 0x3f) | 0x40; + op_map[idx + 2] =3D rec; + rec.opc[1] =3D (rec.opc[1] & 0x3f); + op_map[idx + 3] =3D rec; + } else { + /* add entry unmodified */ + op_map[idx] =3D rec; + } + } + return modreg ? 1 : modmem ? 3 : modcla ? 4 : 1; +} + +static void x86_build_prefix_table(x86_acc_idx *idx, + x86_table_idx tab, x86_opc_data *op_map, size_t *count, + ullong *modfun, ullong *modmod) +{ + /* + * build the opcode map with synthesized prefixes and modrm expansion + */ + size_t n =3D 1; + for (size_t i =3D 0; i < tab.count; i++) { + const x86_opc_data *d =3D x86_opc_table + tab.idx[i]; + const x86_opr_data *o =3D x86_opr_table + d->opr; + const x86_ord_data *p =3D x86_ord_table + d->ord; + + uint type =3D x86_enc_type(d->enc) >> x86_enc_t_shift; + uint prefix =3D x86_enc_prefix(d->enc) >> x86_enc_p_shift; + uint map =3D x86_enc_map(d->enc) >> x86_enc_m_shift; + size_t tpm =3D x86_acc_page(type, prefix, map); + size_t x =3D (tpm << 8) | d->opc[0]; + uint modcla =3D x86_bitmap_get(modfun, x) && x86_bitmap_get(modmod= , x); + x86_opc_prefix tp =3D x86_table_make_prefix(d, o, p); + + x86_opc_data rec =3D *d; + rec.enc |=3D tp.pfx; + n +=3D x86_add_opc_data(op_map, n, rec, + tp.modreg, tp.modmem, modcla); + if (tp.pfx_w) { + rec =3D *d; + rec.enc |=3D tp.pfx | tp.pfx_w; + n +=3D x86_add_opc_data(op_map, n, rec, + tp.modreg, tp.modmem, modcla); + } + if (tp.pfx_o) { + rec =3D *d; + rec.enc |=3D tp.pfx | tp.pfx_o; + n +=3D x86_add_opc_data(op_map, n, rec, + tp.modreg, tp.modmem, modcla); + } + } + + if (count) *count =3D n; +} + +static size_t x86_build_accel_offsets(x86_acc_idx *idx) +{ + /* + * allocate offsets for type prefix map combinations + * + * offset zero means the slice is not allocated but page zero is + * preallocated as a special cased for type:LEX, prefix:0, map:0 + */ + size_t num_pages =3D 1; + for (size_t i =3D 1; i < idx->map_count; i++) { + const x86_opc_data *m =3D idx->map + i; + uint type =3D x86_enc_type(m->enc) >> x86_enc_t_shift; + uint prefix =3D x86_enc_prefix(m->enc) >> x86_enc_p_shift; + uint map =3D x86_enc_map(m->enc) >> x86_enc_m_shift; + size_t acc_page =3D x86_acc_page(type, prefix, map); + if (acc_page > 0 && idx->page_offsets[acc_page] =3D=3D 0) { + size_t page =3D num_pages++; + idx->page_offsets[acc_page] =3D page; + } + } + return num_pages << 8; +} + +static void x86_build_accel_table(x86_acc_idx *idx, x86_acc_entry *acc) +{ + /* + * add entries to the acceleration table. the acceleration + * table contains ranges for all entries of a given opcode. + * + * (type, prefix, map, opcode) -> (index, count) + */ + for (size_t i =3D 1; i < idx->map_count; i++) { + const x86_opc_data *m =3D idx->map + i; + uint type =3D x86_enc_type(m->enc) >> x86_enc_t_shift; + uint prefix =3D x86_enc_prefix(m->enc) >> x86_enc_p_shift; + uint map =3D x86_enc_map(m->enc) >> x86_enc_m_shift; + size_t acc_page =3D x86_acc_page(type, prefix, map); + size_t offset =3D x86_acc_offset(idx, acc_page); + uint opc =3D m->opc[0], opc_i =3D opc, opm =3D m->opm[0]; + while ((opc_i & opm) =3D=3D opc) { + if (acc[offset + opc_i].idx =3D=3D 0) { + acc[offset + opc_i].idx =3D i; + } + acc[offset + opc_i].nent++; + opc_i++; + } + } +} + +static x86_acc_idx *x86_table_build(uint modes) +{ + x86_acc_idx *idx =3D g_malloc0(sizeof(x86_acc_idx)); + x86_table_idx tab =3D x86_opc_table_sorted(x86_opc_table_filter( + x86_opc_table_identity(), modes), x86_sort_numeric); + size_t bmap_size =3D /*t,p,m*/ 512 * /*opcode*/ 256 >> /*bits*/ 3; + ullong *modfun =3D g_malloc0(bmap_size); + ullong *modmod =3D g_malloc0(bmap_size); + x86_build_prefix_clashes(idx, tab, modfun, modmod); + x86_build_prefix_table(idx, tab, NULL, &idx->map_count, modfun, modmod= ); + idx->map =3D g_malloc0(idx->map_count * sizeof(x86_opc_data)); + x86_build_prefix_table(idx, tab, idx->map, NULL, modfun, modmod); + qsort(idx->map, idx->map_count, sizeof(x86_opc_data), + x86_opc_data_compare_build); + idx->page_offsets =3D g_malloc0(/*t,p,m*/ 512); + idx->acc_count =3D x86_build_accel_offsets(idx); + idx->acc =3D g_malloc0(idx->acc_count * sizeof(x86_acc_entry)); + x86_build_accel_table(idx, idx->acc); + g_free(tab.idx); + g_free(modfun); + g_free(modmod); + return idx; +} + +/* + * table lookup + */ + +static x86_opc_data *x86_table_lookup_slow(x86_acc_idx *idx, + const x86_opc_data *m) +{ + size_t begin =3D 0, end =3D idx->map_count; + while (end !=3D 0) { + size_t half =3D (end >> 1), probe =3D begin + half; + if (x86_opc_data_compare_masked(m, idx->map + probe) > 0) { + begin =3D probe + 1; + end -=3D half + 1; + } else { + end =3D half; + } + } + return idx->map + begin; +} + +x86_opc_data *x86_table_lookup(x86_acc_idx *idx, const x86_opc_data *m) +{ + uint type =3D x86_enc_type(m->enc) >> x86_enc_t_shift; + uint prefix =3D x86_enc_prefix(m->enc) >> x86_enc_p_shift; + uint map =3D x86_enc_map(m->enc) >> x86_enc_m_shift; + size_t acc_page =3D x86_acc_page(type, prefix, map); + size_t offset =3D x86_acc_offset(idx, acc_page) + m->opc[0]; + x86_acc_entry *ent =3D x86_acc_lookup(idx, offset); + x86_acc_idx new_idx =3D { ent->nent, idx->map + ent->idx }; + return x86_table_lookup_slow(&new_idx, m); +} + +/* + * table printing utilities + */ + +static x86_table_col x86_new_column(int width, char *data) +{ + x86_table_col col =3D { width, strdup(data) }; + return col; +} + +static void x86_print_row(size_t count, x86_table_col *cols) +{ + printf("|"); + for (size_t i =3D 0; i < count; i++) { + printf(" %-*s |", cols[i].width, cols[i].data); + g_free(cols[i].data); + } + printf("\n"); +} + +static size_t x86_format_enc(char *buf, size_t buflen, const x86_opc_data = *d) +{ + size_t len =3D 0; + + uint s =3D x86_enc_suffix(d->enc); + uint i =3D x86_enc_imm(d->enc); + uint j =3D x86_enc_imm2(d->enc); + uint enc =3D x86_enc_leading(d->enc); + + len +=3D x86_enc_name(buf + len, buflen - len, enc); + + switch (x86_enc_opcode(enc)) { + case x86_enc_o_opcode_r: + len +=3D snprintf(buf + len, buflen - len, " %02hhx+r", d->opc[0]); + break; + default: + len +=3D snprintf(buf + len, buflen - len, " %02hhx", d->opc[0]); + break; + } + + switch (x86_enc_func(enc)) { + case x86_enc_f_modrm_r: + len +=3D snprintf(buf + len, buflen - len, " /r"); + break; + case x86_enc_f_modrm_n: + len +=3D snprintf(buf + len, buflen - len, " /%d", (d->opc[1] >> 3= ) & 7); + break; + case x86_enc_f_opcode_r: + len +=3D snprintf(buf + len, buflen - len, " %02hhx+r", d->opc[1]); + break; + case x86_enc_f_opcode: + len +=3D snprintf(buf + len, buflen - len, " %02hhx", d->opc[1]); + break; + } + + if (i) { + len +=3D x86_enc_name(buf + len, buflen - len, i); + } + if (j) { + len +=3D x86_enc_name(buf + len, buflen - len, j); + } + if (s) { + len +=3D x86_enc_name(buf + len, buflen - len, s); + } + + return len; +} + +void x86_print_op(const x86_opc_data *d, uint compact, uint opcode) +{ + char buf[256]; + x86_table_col cols[6]; + size_t count =3D 0, buflen =3D sizeof(buf), len; + + const x86_opr_data *o =3D x86_opr_table + d->opr; + const x86_ord_data *p =3D x86_ord_table + d->ord; + + buf[(len =3D 0)] =3D '\0'; + if (compact) { + len +=3D snprintf(buf + len, buflen - len, "%s", x86_op_names[d->o= p]); + cols[count++] =3D x86_new_column(18, buf); + } else { + len +=3D snprintf(buf + len, buflen - len, "%s ", x86_op_names[d->= op]); + for (size_t i =3D 0; i < array_size(o->opr) && o->opr[i]; i++) { + if (i !=3D 0) len +=3D snprintf(buf + len, buflen - len, ","); + len +=3D x86_opr_name(buf + len, buflen - len, o->opr[i]); + } + cols[count++] =3D x86_new_column(52, buf); + } + + if (opcode) { + buf[(len =3D 0)] =3D '\0'; + len +=3D snprintf(buf + len, buflen - len, "%02hhx %02hhx", + d->opc[0], d->opc[1]); + cols[count++] =3D x86_new_column(5, buf); + buf[(len =3D 0)] =3D '\0'; + len +=3D snprintf(buf + len, buflen - len, "%02hhx %02hhx", + d->opm[0], d->opm[1]); + cols[count++] =3D x86_new_column(5, buf); + } + + if (compact) { + buf[(len =3D 0)] =3D '\0'; + len +=3D x86_ord_mnem(buf + len, buflen - len, p->ord); + cols[count++] =3D x86_new_column(4, buf); + } + + buf[(len =3D 0)] =3D '\0'; + len +=3D x86_format_enc(buf, buflen - len, d); + cols[count++] =3D x86_new_column(31, buf); + + if (!compact) { + buf[(len =3D 0)] =3D '\0'; + for (size_t i =3D 0; i < array_size(p->ord) && p->ord[i]; i++) { + if (i !=3D 0) len +=3D snprintf(buf + len, buflen - len, ","); + len +=3D x86_ord_name(buf + len, buflen - len, p->ord[i], "/"); + } + cols[count++] =3D x86_new_column(23, buf); + } + + buf[(len =3D 0)] =3D '\0'; + len +=3D x86_mode_name(buf + len, buflen - len, d->mode, "/"); + cols[count++] =3D x86_new_column(8, buf); + + x86_print_row(count, cols); +} + +/* + * encoding / decoding + */ + +int x86_codec_write(x86_ctx *ctx, x86_buffer *buf, x86_codec c, size_t *le= n) +{ + size_t nbytes =3D 0; + + /* segment prefix */ + switch (c.seg) { + case x86_seg_es: nbytes +=3D x86_out8(buf, x86_pb_es); break; + case x86_seg_cs: nbytes +=3D x86_out8(buf, x86_pb_cs); break; + case x86_seg_ss: nbytes +=3D x86_out8(buf, x86_pb_ss); break; + case x86_seg_ds: nbytes +=3D x86_out8(buf, x86_pb_ds); break; + case x86_seg_fs: nbytes +=3D x86_out8(buf, x86_pb_fs); break; + case x86_seg_gs: nbytes +=3D x86_out8(buf, x86_pb_gs); break; + } + + /* other prefixes */ + if (x86_codec_has_osize(&c)) { + nbytes +=3D x86_out8(buf, x86_pb_osize); + } + if (x86_codec_has_asize(&c)) { + nbytes +=3D x86_out8(buf, x86_pb_asize); + } + if (x86_codec_has_wait(&c)) { + nbytes +=3D x86_out8(buf, x86_pb_wait); + } + if (x86_codec_has_lock(&c)) { + nbytes +=3D x86_out8(buf, x86_pb_lock); + } + if (x86_codec_has_rep(&c)) { + nbytes +=3D x86_out8(buf, x86_pb_rep); + } + if (x86_codec_has_repne(&c)) { + nbytes +=3D x86_out8(buf, x86_pb_repne); + } + + /* extended prefixes */ + switch (x86_codec_field_ce(&c) >> x86_ce_shift) { + case x86_ce_rex >> x86_ce_shift: + nbytes +=3D x86_out8(buf, c.rex.data[0]); + break; + case x86_ce_rex2 >> x86_ce_shift: + nbytes +=3D x86_out8(buf, x86_pb_rex2); + nbytes +=3D x86_out8(buf, c.rex2.data[0]); + break; + case x86_ce_vex2 >> x86_ce_shift: + nbytes +=3D x86_out8(buf, x86_pb_vex2); + nbytes +=3D x86_out8(buf, c.vex2.data[0]); + break; + case x86_ce_vex3 >> x86_ce_shift: + nbytes +=3D x86_out8(buf, x86_pb_vex3); + nbytes +=3D x86_out8(buf, c.vex3.data[0]); + nbytes +=3D x86_out8(buf, c.vex3.data[1]); + break; + case x86_ce_evex >> x86_ce_shift: + nbytes +=3D x86_out8(buf, x86_pb_evex); + nbytes +=3D x86_out8(buf, c.evex.data[0]); + nbytes +=3D x86_out8(buf, c.evex.data[1]); + nbytes +=3D x86_out8(buf, c.evex.data[2]); + break; + } + + /* map */ + switch (x86_codec_field_cm(&c) >> x86_cm_shift) { + case x86_cm_none >> x86_cm_shift: + break; + case x86_cm_0f >> x86_cm_shift: + nbytes +=3D x86_out8(buf, 0x0f); + break; + case x86_cm_0f38 >> x86_cm_shift: + nbytes +=3D x86_out16(buf, 0x380f); + break; + case x86_cm_0f3a >> x86_cm_shift: + nbytes +=3D x86_out16(buf, 0x3a0f); + break; + } + + /* opcode */ + for (size_t i =3D 0; i < c.opclen; i++) { + nbytes +=3D x86_out8(buf, c.opc[i]); + } + + /* ModRM and SIB */ + int b; + if (x86_codec_has_modrm(&c)) { + nbytes +=3D x86_out8(buf, c.modrm.data[0]); + + uchar rm =3D x86_modrm_rm(c.modrm.data[0]); + uchar mod =3D x86_modrm_mod(c.modrm.data[0]); + + switch (mod) { + case x86_mod_disp0: + case x86_mod_disp8: + case x86_mod_dispw: + /* there is no SIB in real mode */ + if (!x86_codec_is16(&c) && rm =3D=3D x86_rm_sp_sib) { + nbytes +=3D x86_out8(buf, c.sib.data[0]); + } + break; + case x86_mod_reg: break; + } + switch (mod) { + case x86_mod_disp0: + /* special case for rm/b =3D=3D bp */ + b =3D x86_sib_b(c.sib.data[0]); + if (rm =3D=3D x86_rm_bp_disp0 || + (rm =3D=3D x86_rm_sp_sib && b =3D=3D x86_rm_bp_disp0)) + { + if (x86_codec_is16(&c)) { + nbytes +=3D x86_out16(buf, (u16)c.disp32); + } else { + /* this is RIP-relative in amd64 mode */ + nbytes +=3D x86_out32(buf, (u32)c.disp32); + } + } + break; + case x86_mod_disp8: + nbytes +=3D x86_out8(buf, (u8)c.disp32); + break; + case x86_mod_dispw: + if (x86_codec_is16(&c)) { + nbytes +=3D x86_out16(buf, (u16)c.disp32); break; + } else { + nbytes +=3D x86_out32(buf, (u32)c.disp32); break; + } + case x86_mod_reg: break; + } + } + + /* immediate */ + switch (x86_codec_field_ci(&c) >> x86_ci_shift) { + case x86_ci_iw >> x86_ci_shift: + if (x86_codec_is16(&c) ^ x86_codec_has_osize(&c)) { + nbytes +=3D x86_out16(buf, (u16)c.imm32); + } else { + nbytes +=3D x86_out32(buf, (u32)c.imm32); + } + break; + case x86_ci_iwd >> x86_ci_shift: + if (x86_codec_is16(&c)) { + nbytes +=3D x86_out16(buf, (u16)c.imm32); + } else { + nbytes +=3D x86_out32(buf, (u32)c.imm32); + } + break; + case x86_ci_ib >> x86_ci_shift: + nbytes +=3D x86_out8(buf, (u8)c.imm32); + break; + case x86_ci_i16 >> x86_ci_shift: + nbytes +=3D x86_out16(buf, (u16)c.imm32); + break; + case x86_ci_i32 >> x86_ci_shift: + nbytes +=3D x86_out32(buf, (u32)c.imm32); + break; + case x86_ci_i64 >> x86_ci_shift: + nbytes +=3D x86_out64(buf, (u64)c.imm64); + break; + } + + /* additional immediate used by CALLF/JMPF/ENTER */ + switch (x86_codec_field_cj(&c) >> x86_cj_shift) { + case x86_cj_ib >> x86_cj_shift: + nbytes +=3D x86_out8(buf, (u8)c.imm2); + break; + case x86_cj_i16 >> x86_cj_shift: + nbytes +=3D x86_out16(buf, (u16)c.imm2); + break; + } + + *len =3D nbytes; + return 0; +} + +static int x86_filter_op(x86_codec *c, x86_opc_data *d, uint w) +{ + if (x86_codec_is16(c) && !x86_mode_has16(d->mode)) return -1; + if (x86_codec_is32(c) && !x86_mode_has32(d->mode)) return -1; + if (x86_codec_is64(c) && !x86_mode_has64(d->mode)) return -1; + + switch (x86_codec_field_ce(c) >> x86_ce_shift) { + case x86_ce_rex >> x86_ce_shift: + if (x86_enc_filter_rex(c->rex, d->enc) < 0) return -1; + break; + case x86_ce_rex2 >> x86_ce_shift: + if (x86_enc_filter_rex2(c->rex2, d->enc) < 0) return -1; + break; + case x86_ce_vex2 >> x86_ce_shift: + if (x86_enc_filter_vex2(c->vex2, d->enc) < 0) return -1; + break; + case x86_ce_vex3 >> x86_ce_shift: + if (x86_enc_filter_vex3(c->vex3, d->enc) < 0) return -1; + break; + case x86_ce_evex >> x86_ce_shift: + if (x86_enc_filter_evex(c->evex, d->enc) < 0) return -1; + break; + } + + if (x86_enc_has_a16(d->enc)) { + if (!x86_codec_is16(c) || + !(x86_codec_is32(c) && x86_codec_has_asize(c))) return -1; + } + if (x86_enc_has_a32(d->enc)) { + if (!x86_codec_is32(c) || + !(x86_codec_is64(c) && x86_codec_has_asize(c))) return -1; + } + if (x86_enc_has_a64(d->enc)) { + if (!x86_codec_is64(c) || x86_codec_has_asize(c)) return -1; + } + + if (x86_enc_has_o16(d->enc)) { + switch (x86_enc_width(d->enc)) { + case x86_enc_w_ww: + case x86_enc_w_wx: + if (!(x86_codec_is16(c) ^ x86_codec_has_osize(c)) || w) return= -1; + break; + } + } + if (x86_enc_has_o32(d->enc)) { + switch (x86_enc_width(d->enc)) { + case x86_enc_w_ww: + /* .ww means no 32-bit operands in 64-bit mode */ + if ((x86_codec_is16(c) ^ x86_codec_has_osize(c)) || + x86_codec_is64(c)) return -1; + break; + case x86_enc_w_wx: + if ((x86_codec_is16(c) ^ x86_codec_has_osize(c)) || w) return = -1; + break; + } + } + if (x86_enc_has_o64(d->enc)) { + switch (x86_enc_width(d->enc)) { + case x86_enc_w_ww: + /* .ww means ignores W=3D1 in 64-bit mode */ + if (!x86_codec_is64(c)) return -1; + break; + case x86_enc_w_wx: + if (!x86_codec_is64(c) || !w) return -1; + break; + } + } + + return 0; +} + +static size_t x86_parse_encoding(x86_buffer *buf, x86_codec *c, + x86_opc_data *d) +{ + size_t nbytes =3D 0; + + /* parse SIB and displacement */ + int b; + if (x86_codec_has_modrm(c)) { + uchar rm =3D x86_modrm_rm(c->modrm.data[0]); + uchar mod =3D x86_modrm_mod(c->modrm.data[0]); + switch (mod) { + case x86_mod_disp0: + case x86_mod_disp8: + case x86_mod_dispw: + /* there is no SIB in real mode */ + if (!x86_codec_is16(c) && rm =3D=3D x86_rm_sp_sib) { + c->sib.data[0] =3D (u8)x86_in8(buf); nbytes +=3D 1; + } + break; + case x86_mod_reg: + break; + } + switch (mod) { + case x86_mod_disp0: + /* special case for rm/b =3D=3D bp */ + b =3D x86_sib_b(c->sib.data[0]); + if (rm =3D=3D x86_rm_bp_disp0 || + (rm =3D=3D x86_rm_sp_sib && b =3D=3D x86_rm_bp_disp0)) + { + if (x86_codec_is16(c)) { + c->disp32 =3D (i16)x86_in16(buf); nbytes +=3D 2; + } else { + /* this is RIP-relative in amd64 mode */ + c->disp32 =3D (i32)x86_in32(buf); nbytes +=3D 4; + } + } + break; + case x86_mod_disp8: + c->disp32 =3D (i8)x86_in8(buf); nbytes +=3D 1; + break; + case x86_mod_dispw: + if (x86_codec_is16(c)) { + c->disp32 =3D (i16)x86_in16(buf); nbytes +=3D 2; + } else { + c->disp32 =3D (i32)x86_in32(buf); nbytes +=3D 4; + } + case x86_mod_reg: + break; + } + } + + /* parse immediate */ + switch (x86_enc_imm(d->enc) >> x86_enc_i_shift) { + case x86_enc_i_ib >> x86_enc_i_shift: + c->imm32 =3D (i8)x86_in8(buf); nbytes +=3D 1; + c->flags |=3D x86_ci_ib; + break; + case x86_enc_i_iw >> x86_enc_i_shift: + if (x86_codec_is16(c) ^ x86_codec_has_osize(c)) { + c->imm32 =3D (i16)x86_in16(buf); nbytes +=3D 2; + } else { + c->imm32 =3D (i32)x86_in32(buf); nbytes +=3D 4; + } + c->flags |=3D x86_ci_iw; + break; + case x86_enc_i_iwd >> x86_enc_i_shift: + if (x86_codec_is16(c)) { + c->imm32 =3D (i16)x86_in16(buf); nbytes +=3D 2; + } else { + c->imm32 =3D (i32)x86_in32(buf); nbytes +=3D 4; + } + c->flags |=3D x86_ci_iwd; + break; + case x86_enc_i_i16 >> x86_enc_i_shift: + c->imm32 =3D (i16)x86_in16(buf); nbytes +=3D 2; + c->flags |=3D x86_ci_i16; + break; + case x86_enc_i_i32 >> x86_enc_i_shift: + c->imm32 =3D (i32)x86_in32(buf); nbytes +=3D 4; + c->flags |=3D x86_ci_i32; + break; + case x86_enc_i_i64 >> x86_enc_i_shift: + c->imm64 =3D (i64)x86_in64(buf); nbytes +=3D 8; + c->flags |=3D x86_ci_i64; + break; + } + + /* additional immediate used by CALLF/JMPF/ENTER */ + switch (x86_enc_imm2(d->enc) >> x86_enc_j_shift) { + case x86_enc_j_ib >> x86_enc_j_shift: + c->imm2 =3D (i8)x86_in8(buf); nbytes +=3D 1; + c->flags |=3D x86_cj_ib; + break; + case x86_enc_j_i16 >> x86_enc_j_shift: + c->imm2 =3D (i16)x86_in16(buf); nbytes +=3D 2; + c->flags |=3D x86_cj_i16; + break; + } + + return nbytes; +} + +enum { + x86_enc_tpm_mask =3D x86_enc_t_mask | x86_enc_prexw_mask | x86_enc_m_= mask +}; + +static x86_opc_data *x86_table_match(x86_ctx *ctx, x86_codec *c, + x86_opc_data k, int w) +{ + x86_opc_data *r =3D NULL; + /* key is type+prefix+map with substituted rexw=3Dw flag */ + k.enc =3D ((k.enc & ~x86_enc_p_rexw) | + (-w & x86_enc_p_rexw)) & x86_enc_tpm_mask; + x86_debugf("table_lookup { type:%x prefix:%x map:%x " + "opc:[%02hhx %02hhx] opm:[%02hhx %02hhx] }", + (k.enc & x86_enc_t_mask) >> x86_enc_t_shift, + (k.enc & x86_enc_p_mask) >> x86_enc_p_shift, + (k.enc & x86_enc_m_mask) >> x86_enc_m_shift, + k.opc[0], k.opc[1], k.opm[0], k.opm[1]); + r =3D x86_table_lookup(ctx->idx, &k); + while (r < ctx->idx->map + ctx->idx->map_count) { + /* substitute suffix of record for precise match */ + k.enc =3D ((k.enc & x86_enc_tpm_mask) | + (r->enc & ~x86_enc_tpm_mask)); + size_t oprec =3D (r - ctx->idx->map); + x86_debugf("checking opdata %zu", oprec); + if (debug) x86_print_op(r, 1, 1); + if (x86_opc_data_compare_masked(&k, r) !=3D 0) { + x86_debugf("** no matches"); + r =3D NULL; + break; + } + if (x86_filter_op(c, r, w) =3D=3D 0) break; + r++; + } + return r; +} + +int x86_codec_read(x86_ctx *ctx, x86_buffer *buf, x86_codec *c, size_t *le= n) +{ + uint state =3D x86_state_top; + size_t nbytes =3D 0, limit =3D buf->end - buf->start; + uint t =3D 0, m =3D 0, w =3D 0, p =3D 0, l =3D 0, mode =3D ctx->mode; + x86_opc_data k =3D { 0 }, *r =3D NULL; + uchar b =3D 0, lastp =3D 0; + + memset(c, 0, sizeof(x86_codec)); + switch (mode) { + case x86_modes_32: c->flags |=3D x86_cf_ia32; break; + case x86_modes_64: c->flags |=3D x86_cf_amd64; break; + } + + while (state !=3D x86_state_done) { + nbytes +=3D x86_buffer_read(buf, &b, 1); + switch (state) { + case x86_state_top: + switch (b) { + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + c->rex.data[0] =3D b; + c->flags |=3D x86_ce_rex; + w =3D (c->rex.data[0] >> 3) & 1; + t =3D x86_table_lex; + state =3D x86_state_rex_opcode; + break; + case x86_pb_26: + case x86_pb_2e: + case x86_pb_36: + case x86_pb_3e: + case x86_pb_64: + case x86_pb_65: + state =3D x86_state_segment; + goto segment_reparse; + case x86_pb_66: + case x86_pb_67: + case x86_pb_9b: + case x86_pb_f0: + case x86_pb_f2: + case x86_pb_f3: + state =3D x86_state_legacy; + goto legacy_reparse; + case x86_pb_62: + nbytes +=3D x86_buffer_read(buf, c->evex.data, 3); + c->flags |=3D x86_ce_evex; + m =3D (c->evex.data[0] >> 0) & 7; + w =3D (c->evex.data[1] >> 7) & 1; + p =3D (c->evex.data[1] >> 0) & 3; + l =3D (c->evex.data[2] >> 5) & 3; + t =3D x86_table_evex; + state =3D x86_state_vex_opcode; + break; + case x86_pb_c4: + nbytes +=3D x86_buffer_read(buf, c->vex3.data, 2); + c->flags |=3D x86_ce_vex3; + m =3D (c->vex3.data[0] >> 0) & 31; + w =3D (c->vex3.data[1] >> 7) & 1; + p =3D (c->vex3.data[1] >> 0) & 3; + l =3D (c->vex3.data[1] >> 2) & 1; + t =3D x86_table_vex; + state =3D x86_state_vex_opcode; + break; + case x86_pb_c5: + nbytes +=3D x86_buffer_read(buf, c->vex2.data, 1); + c->flags |=3D x86_ce_vex2; + m =3D x86_map_0f; + p =3D (c->vex2.data[0] >> 0) & 3; + l =3D (c->vex2.data[0] >> 2) & 1; + t =3D x86_table_vex; + state =3D x86_state_vex_opcode; + break; + case x86_pb_d5: + nbytes +=3D x86_buffer_read(buf, c->rex2.data, 1); + c->flags |=3D x86_ce_rex2; + m =3D (c->rex2.data[0] >> 7) & 1; + w =3D (c->rex2.data[0] >> 3) & 1; + t =3D x86_table_lex; + state =3D x86_state_lex_opcode; + break; + case 0x0f: + t =3D x86_table_lex; + state =3D x86_state_map_0f; + break; + default: + m =3D x86_map_none; + t =3D x86_table_lex; + state =3D x86_state_lex_opcode; + goto lex_reparse; + } + break; + case x86_state_segment: segment_reparse: + switch (b) { + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + c->rex.data[0] =3D b; + c->flags |=3D x86_ce_rex; + w =3D (c->rex.data[0] >> 3) & 1; + t =3D x86_table_lex; + state =3D x86_state_rex_opcode; + break; + case x86_pb_26: + c->seg =3D x86_seg_es; state =3D x86_state_legacy; + break; + case x86_pb_2e: + c->seg =3D x86_seg_cs; state =3D x86_state_legacy; + break; + case x86_pb_36: + c->seg =3D x86_seg_ss; state =3D x86_state_legacy; + break; + case x86_pb_3e: + c->seg =3D x86_seg_ds; state =3D x86_state_legacy; + break; + case x86_pb_64: + c->seg =3D x86_seg_fs; state =3D x86_state_legacy; + break; + case x86_pb_65: + c->seg =3D x86_seg_gs; state =3D x86_state_legacy; + break; + case x86_pb_66: + case x86_pb_67: + case x86_pb_9b: + case x86_pb_f0: + case x86_pb_f2: + case x86_pb_f3: + state =3D x86_state_legacy; + goto legacy_reparse; + case x86_pb_62: + case x86_pb_c4: + case x86_pb_c5: + case x86_pb_d5: + goto err; + case 0x0f: + t =3D x86_table_lex; + state =3D x86_state_map_0f; + break; + default: + m =3D x86_map_none; + t =3D x86_table_lex; + state =3D x86_state_lex_opcode; + goto lex_reparse; + } + break; + case x86_state_legacy: legacy_reparse: + switch (b) { + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + c->rex.data[0] =3D b; + c->flags |=3D x86_ce_rex; + w =3D (c->rex.data[0] >> 3) & 1; + t =3D x86_table_lex; + state =3D x86_state_rex_opcode; + break; + case x86_pb_26: + case x86_pb_2e: + case x86_pb_36: + case x86_pb_3e: + case x86_pb_64: + case x86_pb_65: + case x86_pb_62: + case x86_pb_c4: + case x86_pb_c5: + case x86_pb_d5: + goto err; + case x86_pb_66: + lastp =3D b; + c->flags |=3D x86_cp_osize; + break; + case x86_pb_67: + lastp =3D b; + c->flags |=3D x86_cp_asize; + break; + case x86_pb_9b: + lastp =3D b; + c->flags |=3D x86_cp_wait; + break; + case x86_pb_f0: + lastp =3D b; + c->flags |=3D x86_cp_lock; + break; + case x86_pb_f2: + lastp =3D b; + c->flags |=3D x86_cp_repne; + break; + case x86_pb_f3: + lastp =3D b; + c->flags |=3D x86_cp_rep; + break; + case 0x0f: + t =3D x86_table_lex; + state =3D x86_state_map_0f; + break; + default: + m =3D x86_map_none; + t =3D x86_table_lex; + state =3D x86_state_lex_opcode; + goto lex_reparse; + } + break; + case x86_state_rex_opcode: + switch (b) { + case 0x0f: + state =3D x86_state_map_0f; + break; + default: + state =3D x86_state_lex_opcode; + goto lex_reparse; + } + break; + case x86_state_map_0f: + switch (b) { + case 0x38: + c->flags |=3D x86_cm_0f38; + m =3D x86_map_0f38; + state =3D x86_state_lex_opcode; + break; + case 0x3a: + c->flags |=3D x86_cm_0f3a; + m =3D x86_map_0f3a; + state =3D x86_state_lex_opcode; + break; + default: + c->flags |=3D x86_cm_0f; + m =3D x86_map_0f; + state =3D x86_state_lex_opcode; + goto lex_reparse; + } + break; + case x86_state_lex_opcode: lex_reparse: + k.enc |=3D ((t << x86_enc_t_shift) & x86_enc_t_mask) + | ((m << x86_enc_m_shift) & x86_enc_m_mask); + switch (lastp) { + case 0x66: k.enc |=3D x86_enc_p_66; break; + case 0x9b: k.enc |=3D x86_enc_p_9b; break; + case 0xf2: k.enc |=3D x86_enc_p_f2; break; + case 0xf3: k.enc |=3D x86_enc_p_f3; break; + } + state =3D x86_state_done; + break; + case x86_state_vex_opcode: + k.enc |=3D ((t << x86_enc_t_shift) & x86_enc_t_mask) + | ((m << x86_enc_m_shift) & x86_enc_m_mask); + switch (p) { + case x86_pfx_66: k.enc |=3D x86_enc_p_66; break; + case x86_pfx_f2: k.enc |=3D x86_enc_p_f2; break; + case x86_pfx_f3: k.enc |=3D x86_enc_p_f3; break; + } + state =3D x86_state_done; + (void)l; /* l can be added to the index key */ + break; + default: + abort(); + } + }; + + /* populate opcode for table lookup */ + k.mode =3D mode; + c->opc[0] =3D k.opc[0] =3D b; + nbytes +=3D x86_buffer_read(buf, &b, 1); + c->opc[1] =3D k.opc[1] =3D b; + k.opm[0] =3D k.opm[1] =3D 0xff; + + /* if REX.W=3D1 first attempt to lookup W=3D1 record */ + if (w) { + r =3D x86_table_match(ctx, c, k, 1); + } + + /* if REX.W=3D0 or search failed lookup W=3D0/WIG record */ + if (!w || (w && !r)) { + r =3D x86_table_match(ctx, c, k, 0); + } + + /* now attempt lookup without using the prefix */ + if (!r) { + k.enc &=3D ~x86_enc_p_mask; + + /* if REX.W=3D1 first attempt to lookup W=3D1 record */ + if (w) { + r =3D x86_table_match(ctx, c, k, 1); + } + + /* if REX.W=3D0 or search failed lookup W=3D0/WIG record */ + if (!w || (w && !r)) { + r =3D x86_table_match(ctx, c, k, 0); + } + } + + /* parse encoding */ + if (r) { + + /* set opcode length and modrm flags */ + switch (x86_enc_func(r->enc)) { + case x86_enc_f_modrm_r: + case x86_enc_f_modrm_n: + /* second byte is modrm */ + c->flags |=3D x86_cf_modrm; + c->opclen =3D 1; + break; + case x86_enc_f_opcode: + case x86_enc_f_opcode_r: + /* two byte opcode */ + c->opclen =3D 2; + break; + default: + /* no second opcode byte */ + nbytes -=3D x86_buffer_unread(buf, 1); + c->opclen =3D 1; + break; + } + + /* parse SIB, disp, imm from format */ + nbytes +=3D x86_parse_encoding(buf, c, r); + if (nbytes <=3D limit) { + c->rec =3D (r - ctx->idx->map); + *len =3D nbytes; + return 0; + } + } + +err: + nbytes -=3D x86_buffer_unread(buf, nbytes); + *len =3D nbytes; + return -1; +} + +static x86_operands x86_codec_operands(x86_ctx *ctx, x86_codec *c) +{ + x86_operands q; + memset(&q, 0, sizeof(q)); + + const x86_opc_data *d =3D ctx->idx->map + c->rec; + + q.osz =3D x86_codec_has_osize(c); + + if (x86_codec_has_modrm(c)) { + uchar rm =3D x86_modrm_rm(c->modrm.data[0]); + uchar reg =3D x86_modrm_reg(c->modrm.data[0]); + uchar mod =3D x86_modrm_mod(c->modrm.data[0]); + + /* + * q.rm contains unextended value from ModRM.rm + * and is used to indicate SIB/disp encoding. + * + * if SIB present, copy SIB.b into q.b + * if SIB not present, copy ModRM.rm into q.b + * + * q.b contains extended ModRM.rm or SIB.b + */ + + q.mod =3D mod; + q.rm =3D rm; + q.r =3D reg; + + switch (mod) { + case x86_mod_disp0: + case x86_mod_disp8: + case x86_mod_dispw: + if (!x86_codec_is16(c) && rm =3D=3D x86_rm_sp_sib) { + q.b =3D x86_sib_b(c->sib.data[0]); + q.x =3D x86_sib_x(c->sib.data[0]); + q.s =3D x86_sib_s(c->sib.data[0]); + } else { + q.b =3D q.rm; + } + break; + case x86_mod_reg: + q.b =3D q.rm; + break; + } + } else if (d->enc & x86_enc_o_opcode_r) { + q.b =3D c->opc[0] & 7; + } else if (d->enc & x86_enc_f_opcode_r) { + q.b =3D c->opc[1] & 7; + } + + switch (x86_codec_field_ce(c) >> x86_ce_shift) { + case x86_ce_rex >> x86_ce_shift: + q.b |=3D (c->rex.data[0] & 1) << 3; /* [0] -> b[3]*/ + q.x |=3D (c->rex.data[0] & 2) << 2; /* [1] -> x[3]*/ + q.r |=3D (c->rex.data[0] & 4) << 1; /* [2] -> r[3]*/ + q.w =3D (c->rex.data[0] & 8) >> 3; + break; + case x86_ce_rex2 >> x86_ce_shift: + q.b |=3D (c->rex2.data[0] & 1) << 3; /* [0] -> b[3]*/ + q.x |=3D (c->rex2.data[0] & 2) << 2; /* [1] -> x[3]*/ + q.r |=3D (c->rex2.data[0] & 4) << 1; /* [2] -> r[3]*/ + q.w =3D (c->rex2.data[0] & 8) >> 3; + q.b |=3D (c->rex2.data[0] & 16) >> 0; /* [4] -> b[4]*/ + q.x |=3D (c->rex2.data[0] & 32) >> 1; /* [5] -> x[4]*/ + q.r |=3D (c->rex2.data[0] & 64) >> 2; /* [6] -> r[4]*/ + break; + case x86_ce_vex2 >> x86_ce_shift: + q.r |=3D (~c->vex2.data[0] & 128) >> 4; /* [7] -> r[3] */ + q.l =3D (c->vex2.data[0] >> 2) & 1; + q.v =3D (~c->vex2.data[0] >> 3) & 15; + q.osz =3D (c->vex2.data[0] & 3) =3D=3D x86_pfx_66; + break; + case x86_ce_vex3 >> x86_ce_shift: + q.b |=3D (~c->vex3.data[0] & 32) >> 2; /* [5] -> b[3]*/ + q.x |=3D (~c->vex3.data[0] & 64) >> 3; /* [6] -> x[3]*/ + q.r |=3D (~c->vex3.data[0] & 128) >> 4; /* [7] -> r[3]*/ + q.l =3D (c->vex3.data[1] >> 2) & 1; + q.v =3D (~c->vex3.data[1] >> 3) & 15; + q.w =3D (c->vex3.data[1] >> 7) & 1; + q.osz =3D (c->vex3.data[1] & 3) =3D=3D x86_pfx_66; + break; + case x86_ce_evex >> x86_ce_shift: + q.b |=3D (~c->evex.data[0] & 32) >> 2; /* [5] -> b[3]*/ + q.x |=3D (~c->evex.data[0] & 64) >> 3; /* [6] -> x[3]*/ + q.r |=3D (~c->evex.data[0] & 128) >> 4; /* [7] -> r[3]*/ + q.b |=3D (c->evex.data[0] & 8) << 1; /* [3] -> b[4]*/ + q.x |=3D (~c->evex.data[1] & 4) << 2; /* [2] -> x[4]*/ + q.r |=3D (~c->evex.data[0] & 16) >> 0; /* [4] -> r[4]*/ + q.v =3D (~c->evex.data[1] >> 3) & 15; + q.v |=3D (~c->evex.data[2] & 8) << 1; /* [3] -> v[4]*/ + q.k =3D (c->evex.data[2] >> 0) & 7; + q.l =3D (c->evex.data[2] >> 5) & 3; + q.brd =3D (c->evex.data[2] >> 4) & 1; + q.osz =3D (c->evex.data[1] & 3) =3D=3D x86_pfx_66; + break; + } + + return q; +} + +/* + * disassembly + */ + +static inline x86_arg x86_codec_meta(uint enc, uint opr, uint ord, + x86_operands q) +{ + x86_arg a =3D { enc, opr, ord, q }; + return a; +} + +static uint x86_codec_addr_size(x86_codec *c) +{ + /* todo - handle address size prefix */ + if (x86_codec_is32(c)) return x86_opr_size_32; + if (x86_codec_is64(c)) return x86_opr_size_64; + return x86_opr_size_16; +} + +static const char *x86_ptr_size_str(uint sz) +{ + switch (sz) { + case x86_opr_size_8: return "byte ptr "; + case x86_opr_size_16: return "word ptr "; + case x86_opr_size_32: return "dword ptr "; + case x86_opr_size_64: return "qword ptr "; + case x86_opr_size_80: return "tbyte ptr "; + case x86_opr_size_128: return "xmmword ptr "; + case x86_opr_size_256: return "ymmword ptr "; + case x86_opr_size_512: return "zmmword ptr "; + default: return ""; + } +} + +static uint x86_opr_reg_size(x86_codec *c, x86_arg a) +{ + uint oprty =3D x86_opr_type_val(a.opr); + uint oprsz =3D x86_opr_size_val(a.opr); + uint oprmem =3D x86_opr_mem_val(a.opr); + + /* 'rw' or 'mw' deduce size from mode, operand size prefix and REX.W */ + if ((oprty =3D=3D x86_opr_reg && oprsz =3D=3D x86_opr_size_w) || + (oprmem =3D=3D x86_opr_mw) || + (a.opr =3D=3D x86_opr_moffs || a.opr =3D=3D x86_opr_reg_psi || + a.opr =3D=3D x86_opr_reg_pdi)) + { + switch (x86_enc_width(a.enc)) { + case x86_enc_w_wb: return x86_opr_size_8; + case x86_enc_w_ww: + if (x86_codec_is16(c)) + return a.q.osz ? x86_opr_size_32 : x86_opr_size_16; + if (x86_codec_is32(c)) + return a.q.osz ? x86_opr_size_16 : x86_opr_size_32; + if (x86_codec_is64(c)) + return a.q.osz ? x86_opr_size_16 : x86_opr_size_64; + break; + case x86_enc_w_wx: + if (x86_codec_is16(c)) + return a.q.osz ? x86_opr_size_32 : x86_opr_size_16; + if (x86_codec_is32(c)) + return a.q.osz ? x86_opr_size_16 : x86_opr_size_32; + if (x86_codec_is64(c)) + return a.q.osz ? x86_opr_size_16 : + a.q.w ? x86_opr_size_64 : x86_opr_size_32; + break; + case x86_enc_w_w0: return x86_opr_size_32; + case x86_enc_w_w1: return x86_opr_size_64; + default: break; + } + } + + /* operand contains the register size */ + if (oprsz !=3D 0 && oprsz !=3D x86_opr_size_w && oprsz !=3D x86_opr_si= ze_a) { + return oprsz; + } + + return 0; +} + +static uint x86_opr_ptr_size(x86_codec *c, x86_arg a) +{ + uint memsz =3D x86_opr_mem_size(a.opr); + if (memsz =3D=3D x86_opr_size_w) { + memsz =3D x86_opr_reg_size(c, a); + } + return memsz; +} + +static uint x86_sized_gpr(x86_codec *c, uint reg, uint opr) +{ + switch (x86_opr_size_val(opr)) { + case x86_opr_size_8: + /* legacy encoding selects ah/cd/dh/bh instead of spl/bpl/sil/dil = */ + if ((x86_codec_field_ce(c)) =3D=3D x86_ce_none && + ((reg & 31) >=3D 4 && (reg & 31) < 8)) return x86_reg_bl | (reg= & 31); + return x86_reg_b | (reg & 31); + case x86_opr_size_16: return x86_reg_w | (reg & 31); + case x86_opr_size_32: return x86_reg_d | (reg & 31); + case x86_opr_size_64: return x86_reg_q | (reg & 31); + default: return reg; + } +} + +static uint x86_sized_vec(uint reg, uint opr) +{ + switch (x86_opr_size_val(opr)) { + case x86_opr_size_64: return x86_reg_mmx | (reg & 7); + case x86_opr_size_128: return x86_reg_xmm | (reg & 31); + case x86_opr_size_256: return x86_reg_ymm | (reg & 31); + case x86_opr_size_512: return x86_reg_zmm | (reg & 31); + default: return reg; + } +} + +static uint x86_regsz_bytes(uint regsz) +{ + switch (regsz) { + case x86_opr_size_8: return 1; + case x86_opr_size_16: return 2; + case x86_opr_size_32: return 4; + case x86_opr_size_64: return 8; + case x86_opr_size_128: return 16; + case x86_opr_size_256: return 32; + case x86_opr_size_512: return 64; + default: break; + } + return 1; +} + +static size_t x86_opr_intel_reg_str_internal(char *buf, size_t buflen, + x86_codec *c, x86_arg a, uint reg) +{ + size_t len =3D 0; + + switch (x86_opr_type_val(a.opr)) { + case x86_opr_reg: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_sized_gpr(c, reg, + x86_opr_reg_size(c, a)))); break; + case x86_opr_vec: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_sized_vec(reg, a.opr))); break; + case x86_opr_k: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_reg_kmask | (reg & 7))); break; + case x86_opr_mmx: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_reg_mmx | (reg & 7))); break; + case x86_opr_st: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_reg_fpu | (reg & 7))); break; + case x86_opr_bnd: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_reg_bnd | (reg & 7))); break; + case x86_opr_seg: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_reg_sreg | (reg & 7))); break; + case x86_opr_creg: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_reg_creg | (reg & 15))); break; + case x86_opr_dreg: len =3D xsnprintf(buf, buflen, "%s", + x86_reg_name(x86_reg_dreg | (reg & 15))); break; + default: len =3D xsnprintf(buf, buflen, "%s", "unknown"); break; + } + + if ((a.q.k & 7) > 0 && (a.opr & x86_opr_flag_k) !=3D 0) { + len +=3D xsnprintf(buf + len, buflen - len, " {%s}", + x86_reg_name(x86_reg_kmask | (a.q.k & 7))); + } + + return len; +} + +static uint x86_opr_bcst_size(uint opr) +{ + switch (x86_opr_bcst_val(opr)) { + case x86_opr_m16bcst: return x86_opr_size_16; + case x86_opr_m32bcst: return x86_opr_size_32; + case x86_opr_m64bcst: return x86_opr_size_64; + } + return 0; +} + +x86_opr_formats x86_opr_formats_intel_hex =3D +{ + .ptr_rip =3D "%s[rip]", + .ptr_rip_disp =3D "%s[rip %s 0x%x]", + .ptr_reg =3D "%s[%s]", + .ptr_reg_disp =3D "%s[%s %s 0x%x]", + .ptr_reg_sreg =3D "%s[%s + %d*%s]", + .ptr_reg_sreg_disp =3D "%s[%s + %d*%s %s 0x%x]", + .ptr_reg_reg =3D "%s[%s + %s]", + .ptr_reg_reg_disp =3D "%s[%s + %s %s 0x%x]", + .ptr_sreg =3D "%s[%d*%s]", + .ptr_disp =3D "%s[%s0x%x]", + .ptr_imm64 =3D "%s[%s0x%llx]", + .ptr_imm32 =3D "%s[%s0x%x]", + .imm64 =3D "%s0x%llx", + .imm32 =3D "%s0x%x", + .reg =3D "%s", +}; + +x86_opr_formats x86_opr_formats_intel_dec =3D +{ + .ptr_rip =3D "%s[rip]", + .ptr_rip_disp =3D "%s[rip %s %u]", + .ptr_reg =3D "%s[%s]", + .ptr_reg_disp =3D "%s[%s %s %u]", + .ptr_reg_sreg =3D "%s[%s + %d*%s]", + .ptr_reg_sreg_disp =3D "%s[%s + %d*%s %s %u]", + .ptr_reg_reg =3D "%s[%s + %s]", + .ptr_reg_reg_disp =3D "%s[%s + %s %s %u]", + .ptr_sreg =3D "%s[%d*%s]", + .ptr_disp =3D "%s[%s%u]", + .ptr_imm64 =3D "%s[%s%llu]", + .ptr_imm32 =3D "%s[%s%u]", + .imm64 =3D "%s%llu", + .imm32 =3D "%s%u", + .reg =3D "%s", +}; + +static size_t x86_opr_intel_mrm_str_internal(char *buf, size_t buflen, + x86_codec *c, x86_arg a, x86_opr_formats *fmt) +{ + uint regsz =3D x86_opr_reg_size(c, a); + uint ptrsz =3D x86_opr_ptr_size(c, a); + uint addrsz =3D x86_codec_addr_size(c); + uint bcstsz =3D x86_opr_bcst_size(a.opr); + uint oprmem =3D x86_opr_mem_val(a.opr); + uint vmsz =3D x86_opr_ew_size(a.opr); + size_t len =3D 0; + + int is_disp =3D c->disp32 !=3D 0; + int is_scale =3D a.q.s !=3D 0; + int is_sib =3D a.q.rm =3D=3D x86_sp; + int is_vsib =3D oprmem =3D=3D x86_opr_vm32 || oprmem =3D=3D x86_opr_vm= 64; + int is_reg =3D a.q.mod =3D=3D x86_mod_reg; + int is_disp0 =3D a.q.mod =3D=3D x86_mod_disp0; + int is_disp8 =3D a.q.mod =3D=3D x86_mod_disp8; + int is_base_bp =3D (a.q.b & 7) =3D=3D x86_bp; + int is_base_sp =3D (a.q.b & 7) =3D=3D x86_sp; + int is_index_sp =3D a.q.x =3D=3D x86_sp; + int is_64bit =3D x86_codec_is64(c); + int is_evex =3D x86_codec_field_ce(c) =3D=3D x86_ce_evex; + + int is_ptr_rip =3D is_base_bp && is_disp0 && !is_sib && is_64bit; + int is_ptr_rip_disp =3D is_ptr_rip && is_disp; + int is_ptr_disp =3D is_base_bp && is_disp0 && (!is_sib || + (is_sib && !is_vsib && is_index_sp && !is_scale)); + int is_ptr_sreg =3D is_sib && is_base_bp && is_disp0; + int is_ptr_reg_sreg =3D is_sib && is_scale; + int is_ptr_reg_sreg_disp =3D is_ptr_reg_sreg && is_disp; + int is_ptr_reg_reg =3D is_sib && !(is_base_sp && is_index_sp && !is_vs= ib); + int is_ptr_reg_reg_disp =3D is_ptr_reg_reg && is_disp; + + int s =3D (1 << a.q.s); + uint d =3D c->disp32 < 0 ? -c->disp32 : c->disp32; + + const char *so =3D c->disp32 < 0 ? "-" : "+"; + const char *sn =3D c->disp32 < 0 ? "-" : ""; + const char *p =3D is_vsib ? x86_ptr_size_str(vmsz) : x86_ptr_size_str(= ptrsz); + const char *b =3D x86_reg_name(x86_sized_gpr(c, a.q.b, addrsz)); + const char *x =3D is_vsib ? x86_reg_name(x86_sized_vec(a.q.x, regsz)) : + is_index_sp ? "riz" : x86_reg_name(x86_sized_gpr(c, a.q.x, addrsz)= ); + + if (is_disp8 && is_evex) { + d *=3D x86_opr_et_val(a.opr) ? + x86_opr_ew_bytes(a.opr) : x86_regsz_bytes(ptrsz); + } + + if (is_reg) { + len =3D x86_opr_intel_reg_str_internal(buf, buflen, c, a, a.q.b); + } else if (is_ptr_rip_disp) { + len =3D xsnprintf(buf, buflen, fmt->ptr_rip_disp, p, so, d); + } else if (is_ptr_rip) { + len =3D xsnprintf(buf, buflen, fmt->ptr_rip, p); + } else if (is_ptr_disp) { + len =3D xsnprintf(buf, buflen, fmt->ptr_disp, p, sn, d); + } else if (is_ptr_sreg) { + len =3D xsnprintf(buf, buflen, fmt->ptr_sreg, p, s, x); + } else if (is_ptr_reg_sreg_disp) { + len =3D xsnprintf(buf, buflen, fmt->ptr_reg_sreg_disp, p, b, s, x,= so, d); + } else if (is_ptr_reg_sreg) { + len =3D xsnprintf(buf, buflen, fmt->ptr_reg_sreg, p, b, s, x); + } else if (is_ptr_reg_reg_disp) { + len =3D xsnprintf(buf, buflen, fmt->ptr_reg_reg_disp, p, b, x, so,= d); + } else if (is_ptr_reg_reg) { + len =3D xsnprintf(buf, buflen, fmt->ptr_reg_reg, p, b, x); + } else if (is_disp) { + len =3D xsnprintf(buf, buflen, fmt->ptr_reg_disp, p, b, so, d); + } else { + len =3D xsnprintf(buf, buflen, fmt->ptr_reg, p, b); + } + + if (!is_reg && (a.q.k & 7) > 0 && (a.opr & x86_opr_flag_k) !=3D 0) { + const char *k =3D x86_reg_name(x86_reg_kmask | (a.q.k & 7)); + len +=3D xsnprintf(buf + len, buflen - len, " {%s}", k); + } + + if (bcstsz && a.q.brd) { + int bcstsc =3D x86_regsz_bytes(ptrsz) / x86_regsz_bytes(bcstsz); + len +=3D xsnprintf(buf + len, buflen - len, "{1to%u}", bcstsc); + } + + return len; +} + +static size_t x86_opr_intel_mrm_dec_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + return x86_opr_intel_mrm_str_internal(buf, buflen, c, a, + &x86_opr_formats_intel_dec); +} + +static size_t x86_opr_intel_mrm_hex_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + return x86_opr_intel_mrm_str_internal(buf, buflen, c, a, + &x86_opr_formats_intel_hex); +} + +static size_t x86_opr_intel_reg_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + return x86_opr_intel_reg_str_internal(buf, buflen, c, a, a.q.r); +} + +static size_t x86_opr_intel_vec_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + return x86_opr_intel_reg_str_internal(buf, buflen, c, a, a.q.v); +} + +static size_t x86_opr_intel_opb_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + return x86_opr_intel_reg_str_internal(buf, buflen, c, a, a.q.b); +} + +static size_t x86_opr_intel_is4_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + uint reg =3D (c->imm32 >> 4) & 15; + return x86_opr_intel_reg_str_internal(buf, buflen, c, a, reg); +} + +static size_t x86_opr_intel_imm_str_internal(char *buf, size_t buflen, + x86_codec *c, x86_arg a, x86_opr_formats *fmt) +{ + if (a.opr =3D=3D x86_opr_moffs) { + uint regsz =3D x86_opr_reg_size(c, a); + if ((x86_codec_field_ci(c)) =3D=3D x86_ci_i64) { + llong imm =3D c->imm64; + return xsnprintf(buf, buflen, fmt->ptr_imm64, + x86_ptr_size_str(regsz), + imm < 0 ? "-" : "", imm < 0 ? -imm : imm); + } else { + int imm =3D c->imm32; + return xsnprintf(buf, buflen, fmt->ptr_imm32, + x86_ptr_size_str(regsz), + imm < 0 ? "-" : "", imm < 0 ? -imm : imm); + } + } else { + if ((x86_codec_field_ci(c)) =3D=3D x86_ci_i64) { + llong imm =3D c->imm64; + return xsnprintf(buf, buflen, fmt->imm64, + imm < 0 ? "-" : "", imm < 0 ? -imm : imm); + } else { + int imm =3D c->imm32; + return xsnprintf(buf, buflen, fmt->imm32, + imm < 0 ? "-" : "", imm < 0 ? -imm : imm); + } + } +} + +static size_t x86_opr_intel_imm_hex_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + return x86_opr_intel_imm_str_internal(buf, buflen, c, a, + &x86_opr_formats_intel_hex); +} + +static size_t x86_opr_intel_imm_dec_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + return x86_opr_intel_imm_str_internal(buf, buflen, c, a, + &x86_opr_formats_intel_dec); +} + +static size_t x86_opr_intel_ime_hex_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + int imm =3D c->imm2; + return xsnprintf(buf, buflen, "%s0x%x", + imm < 0 ? "-" : "", imm < 0 ? -imm : imm); +} + +static size_t x86_opr_intel_ime_dec_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a) +{ + int imm =3D c->imm2; + return xsnprintf(buf, buflen, "%s%u", + imm < 0 ? "-" : "", imm < 0 ? -imm : imm); +} + +static size_t x86_opr_intel_rel_hex_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a, size_t pc_offset, x86_fmt_symbol sym_cb) +{ + size_t len =3D x86_opr_intel_imm_str_internal(buf, buflen, c, a, + &x86_opr_formats_intel_hex); + if (sym_cb) { + len +=3D sym_cb(buf + len, buflen - len, c, pc_offset); + } + return len; +} + +static size_t x86_opr_intel_rel_dec_str(char *buf, size_t buflen, + x86_codec *c, x86_arg a, size_t pc_offset, x86_fmt_symbol sym_cb) +{ + size_t len =3D x86_opr_intel_imm_str_internal(buf, buflen, c, a, + &x86_opr_formats_intel_dec); + if (sym_cb) { + len +=3D sym_cb(buf + len, buflen - len, c, pc_offset); + } + return len; +} + +static uint x86_opr_intel_const_reg(x86_codec *c, + x86_arg a) +{ + uint regsz =3D x86_opr_reg_size(c, a); + uint addrsz =3D x86_codec_addr_size(c); + + switch (a.opr) { + case x86_opr_reg_al: return x86_al; + case x86_opr_reg_cl: return x86_cl; + case x86_opr_reg_ax: return x86_ax; + case x86_opr_reg_cx: return x86_cx; + case x86_opr_reg_dx: return x86_dx; + case x86_opr_reg_bx: return x86_bx; + case x86_opr_reg_eax: return x86_eax; + case x86_opr_reg_ecx: return x86_ecx; + case x86_opr_reg_edx: return x86_edx; + case x86_opr_reg_ebx: return x86_ebx; + case x86_opr_reg_rax: return x86_rax; + case x86_opr_reg_rcx: return x86_rcx; + case x86_opr_reg_rdx: return x86_rdx; + case x86_opr_reg_rbx: return x86_rbx; + case x86_opr_reg_aw: return x86_sized_gpr(c, x86_al, regsz); + case x86_opr_reg_cw: return x86_sized_gpr(c, x86_cl, regsz); + case x86_opr_reg_dw: return x86_sized_gpr(c, x86_dl, regsz); + case x86_opr_reg_bw: return x86_sized_gpr(c, x86_bl, regsz); + case x86_opr_reg_pa: return x86_sized_gpr(c, x86_al, addrsz); + case x86_opr_reg_pc: return x86_sized_gpr(c, x86_cl, addrsz); + case x86_opr_reg_pd: return x86_sized_gpr(c, x86_dl, addrsz); + case x86_opr_reg_pb: return x86_sized_gpr(c, x86_bl, addrsz); + default: break; + } + return -1; +} + +static size_t x86_opr_intel_const_str(char *buf, size_t buflen, x86_codec = *c, + x86_arg a) +{ + uint regsz =3D x86_opr_reg_size(c, a); + uint addrsz =3D x86_codec_addr_size(c); + int regname =3D x86_opr_intel_const_reg(c, a); + + if (regname >=3D 0) { + return xsnprintf(buf, buflen, "%s", x86_reg_name(regname)); + } + + switch (a.opr) { + case x86_opr_1: + return xsnprintf(buf, buflen, "1"); + case x86_opr_reg_xmm0: + return xsnprintf(buf, buflen, "%s", "xmm0"); + case x86_opr_reg_xmm0_7: + return xsnprintf(buf, buflen, "%s", "xmm0_7"); + case x86_opr_seg_fs: + return xsnprintf(buf, buflen, "fs"); + case x86_opr_seg_gs: + return xsnprintf(buf, buflen, "gs"); + case x86_opr_reg_st0: + return xsnprintf(buf, buflen, "st"); + case x86_opr_reg_psi: + return xsnprintf(buf, buflen, "%s[%s]", + x86_ptr_size_str(regsz), + x86_reg_name(x86_sized_gpr(c, x86_sil, addrsz))); + case x86_opr_reg_pdi: + return xsnprintf(buf, buflen, "%s[%s]", + x86_ptr_size_str(regsz), + x86_reg_name(x86_sized_gpr(c, x86_dil, addrsz))); + default: return xsnprintf(buf, buflen, "%s", "unknown"); + } +} + +x86_opr_formatter x86_format_intel_hex =3D +{ + .fmt_const =3D &x86_opr_intel_const_str, + .fmt_imm =3D &x86_opr_intel_imm_hex_str, + .fmt_reg =3D &x86_opr_intel_reg_str, + .fmt_mrm =3D &x86_opr_intel_mrm_hex_str, + .fmt_vec =3D &x86_opr_intel_vec_str, + .fmt_opb =3D &x86_opr_intel_opb_str, + .fmt_is4 =3D &x86_opr_intel_is4_str, + .fmt_ime =3D &x86_opr_intel_ime_hex_str, + .fmt_rel =3D &x86_opr_intel_rel_hex_str +}; + +x86_opr_formatter x86_format_intel_dec =3D +{ + .fmt_const =3D &x86_opr_intel_const_str, + .fmt_imm =3D &x86_opr_intel_imm_dec_str, + .fmt_reg =3D &x86_opr_intel_reg_str, + .fmt_mrm =3D &x86_opr_intel_mrm_dec_str, + .fmt_vec =3D &x86_opr_intel_vec_str, + .fmt_opb =3D &x86_opr_intel_opb_str, + .fmt_is4 =3D &x86_opr_intel_is4_str, + .fmt_ime =3D &x86_opr_intel_ime_dec_str, + .fmt_rel =3D &x86_opr_intel_rel_dec_str +}; + +static size_t x86_format_operand(char *buf, size_t buflen, x86_codec *c, + x86_arg a, size_t pc_offset, x86_fmt_symbol sym_cb, x86_opr_formatter = *fmt) +{ + switch (x86_ord_type_val(a.ord)) { + case x86_ord_const: + return fmt->fmt_const(buf, buflen, c, a); + case x86_ord_reg: + return fmt->fmt_reg(buf, buflen, c, a); + case x86_ord_mrm: + return fmt->fmt_mrm(buf, buflen, c, a); + case x86_ord_vec: + return fmt->fmt_vec(buf, buflen, c, a); + case x86_ord_opr: + return fmt->fmt_opb(buf, buflen, c, a); + case x86_ord_imm: + if (a.opr =3D=3D x86_opr_rel8 || a.opr =3D=3D x86_opr_relw) { + return fmt->fmt_rel(buf, buflen, c, a, pc_offset, sym_cb); + } else if ((a.ord & ~x86_ord_flag_mask) =3D=3D x86_ord_is4) { + return fmt->fmt_is4(buf, buflen, c, a); + } else if ((a.ord & ~x86_ord_flag_mask) =3D=3D x86_ord_ime) { + return fmt->fmt_ime(buf, buflen, c, a); + } else { + return fmt->fmt_imm(buf, buflen, c, a); + } + default: return 0; + } +} + +static size_t x86_format_op_internal(char *buf, size_t buflen, x86_ctx *ct= x, + x86_codec *c, size_t pc_offset, x86_fmt_symbol sym_cb) +{ + const x86_opc_data *d =3D ctx->idx->map + c->rec; + const x86_opr_data *o =3D x86_opr_table + d->opr; + const x86_ord_data *s =3D x86_ord_table + d->ord; + + x86_operands q =3D x86_codec_operands(ctx, c); + + size_t len =3D 0; + uint prefix =3D d->enc & x86_enc_p_mask; + + if (x86_codec_has_lock(c)) { + len +=3D xsnprintf(buf + len, buflen - len, "lock "); + } + if (x86_codec_has_rep(c) && prefix !=3D x86_enc_p_f3) { + len +=3D xsnprintf(buf + len, buflen - len, "rep "); + } + if (x86_codec_has_repne(c) && prefix !=3D x86_enc_p_f2) { + len +=3D xsnprintf(buf + len, buflen - len, "repne "); + } + if (x86_codec_has_wait(c) && prefix !=3D x86_enc_p_9b) { + len +=3D xsnprintf(buf + len, buflen - len, "wait "); + } + + len +=3D xsnprintf(buf + len, buflen - len, "%s", x86_op_names[d->op]); + + for (size_t i =3D 0; i < array_size(o->opr) && o->opr[i]; i++) { + x86_arg a =3D x86_codec_meta(d->enc, o->opr[i], s->ord[i], q); + len +=3D xsnprintf(buf + len, buflen - len, i =3D=3D 0 ? "\t" : ",= "); + len +=3D x86_format_operand(buf + len, buflen - len, c, a, + pc_offset, sym_cb, &x86_format_intel_dec); + } + + return len; +} + +size_t x86_format_op(char *buf, size_t buflen, x86_ctx *ctx, x86_codec *c) +{ + return x86_format_op_internal(buf, buflen, ctx, c, 0, NULL); +} + +size_t x86_format_op_symbol(char *buf, size_t buflen, x86_ctx *ctx, + x86_codec *c, size_t pc_offset, x86_fmt_symbol sym_cb) +{ + /* note: caller needs to add instruction length to pc_offset */ + return x86_format_op_internal(buf, buflen, ctx, c, pc_offset, sym_cb); +} + +size_t x86_format_hex(char *buf, size_t buflen, uchar *data, size_t datale= n) +{ + size_t len =3D 0; + for (size_t i =3D 0; i < datalen && i < 11; i++) { + len +=3D xsnprintf(buf + len, buflen - len, i =3D=3D 0 ? "\t" : " = "); + len +=3D xsnprintf(buf + len, buflen - len, "%02hhx", data[i]); + } + size_t tabs =3D datalen < 10 ? (40 - datalen * 3) / 8 : 1; + for (size_t i =3D 0; i < tabs ; i++) { + len +=3D xsnprintf(buf + len, buflen - len, "\t"); + } + return len; +} + +/* + * context + */ + +x86_ctx *x86_ctx_create(uint mode) +{ + x86_ctx *ctx =3D g_malloc(sizeof(x86_ctx)); + ctx->mode =3D mode; + ctx->idx =3D x86_table_build(mode); + return ctx; +} + +void x86_ctx_destroy(x86_ctx *ctx) +{ + g_free(ctx->idx->page_offsets); + g_free(ctx->idx->map); + g_free(ctx->idx->acc); + g_free(ctx); +} diff --git a/disas/x86-disas.c b/disas/x86-disas.c new file mode 100644 index 000000000000..9ea21f26075b --- /dev/null +++ b/disas/x86-disas.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024-2025 Michael Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software= "), + * to deal in the Software without restriction, including without limitati= on + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL= ITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "disas/dis-asm.h" +#include "disas/x86.h" + +static size_t format_hex(char *buf, size_t buflen, uchar *data, size_t nby= tes) +{ + size_t len =3D 0; + size_t indent =3D 1; + + const size_t hexcols =3D 10; + + for (size_t i =3D 0; i < nbytes; i++) { + len +=3D snprintf(buf + len, buflen - len, " %02x" + (i =3D=3D 0),= data[i]); + } + if (hexcols - nbytes < hexcols) { + indent =3D (hexcols - nbytes) * 3 + 8 - (hexcols * 3) % 8; + } + for (size_t i =3D 0; i < indent && len < (buflen - 1); i++) { + buf[len++] =3D ' '; + } + buf[len] =3D '\0'; + + return len; +} + +static size_t format_symbol(char *buf, size_t buflen, x86_codec *c, + size_t pc_offset) +{ + ullong addr =3D pc_offset + c->imm32; + return snprintf(buf, buflen, " # 0x%llx", addr); +} + +int print_insn_x86(bfd_vma memaddr, struct disassemble_info *info) +{ + x86_buffer buf; + x86_codec codec; + x86_ctx *ctx; + bfd_byte *packet; + size_t nfetch, ndecode, len; + char str[128]; + int ret; + + static const size_t max_fetch_len =3D 16; + + /* read instruction */ + nfetch =3D info->buffer_vma + info->buffer_length - memaddr; + if (nfetch > max_fetch_len) { + nfetch =3D max_fetch_len; + } + packet =3D alloca(nfetch); + ret =3D (*info->read_memory_func)(memaddr, packet, nfetch, info); + if (ret !=3D 0) { + (*info->memory_error_func)(ret, memaddr, info); + return ret; + } + + /* decode instruction */ + ctx =3D (x86_ctx *)info->private_data; + x86_buffer_init_ex(&buf, packet, 0, nfetch); + ret =3D x86_codec_read(ctx, &buf, &codec, &ndecode); + if (ret !=3D 0) { + return -1; + } + + /* format instruction */ + len =3D format_hex(str, sizeof(str), packet, ndecode); + x86_format_op_symbol(str + len, sizeof(str) - len, ctx, &codec, + memaddr + ndecode, format_symbol); + (*info->fprintf_func)(info->stream, "%s", str); + + return ndecode; +} diff --git a/disas/x86.h b/disas/x86.h new file mode 100644 index 000000000000..87e87a0dcb92 --- /dev/null +++ b/disas/x86.h @@ -0,0 +1,1858 @@ +/* + * Copyright (c) 2024-2025 Michael Clark + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software= "), + * to deal in the Software without restriction, including without limitati= on + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL= ITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include +#include + +#include "qemu/bswap.h" + +/* + * types + */ + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; +typedef unsigned long long ullong; +typedef long long llong; + +typedef char i8; +typedef short i16; +typedef int i32; +typedef llong i64; + +typedef uchar u8; +typedef ushort u16; +typedef uint u32; +typedef ullong u64; + +/* + * x86 forward declarations + */ + +typedef struct x86_rex x86_rex; +typedef struct x86_rex2 x86_rex2; +typedef struct x86_vex2 x86_vex2; +typedef struct x86_vex3 x86_vex3; +typedef struct x86_evex x86_evex; +typedef struct x86_modrm x86_modrm; +typedef struct x86_sib x86_sib; + +typedef struct x86_mem x86_mem; +typedef struct x86_codec x86_codec; +typedef struct x86_modeb x86_modeb; +typedef struct x86_opc_data x86_opc_data; +typedef struct x86_opr_data x86_opr_data; +typedef struct x86_ord_data x86_ord_data; +typedef struct x86_table_idx x86_table_idx; +typedef struct x86_acc_idx x86_acc_idx; +typedef struct x86_acc_entry x86_acc_entry; +typedef struct x86_buffer x86_buffer; +typedef struct x86_ctx x86_ctx; + +/* + * simple debug macros + */ + +#define VA_ARGS(...) , ##__VA_ARGS__ +#define x86_debug(fmt, ...) if (debug) \ + printf(fmt "\n" VA_ARGS(__VA_ARGS__)) +#define x86_debugf(fmt, ...) if (debug) \ + printf("%s: " fmt "\n", __func__ VA_ARGS(__VA_ARGS__)) + +/* + * register groups + */ + +enum +{ + x86_reg_w =3D (0 << 5), + x86_reg_b =3D (1 << 5), + x86_reg_d =3D (2 << 5), + x86_reg_q =3D (3 << 5), + + x86_reg_mmx =3D (4 << 5), + x86_reg_xmm =3D (5 << 5), + x86_reg_ymm =3D (6 << 5), + x86_reg_zmm =3D (7 << 5), + + x86_reg_kmask =3D (8 << 5), + x86_reg_bl =3D (9 << 5), + x86_reg_fpu =3D (10 << 5), + x86_reg_bnd =3D (11 << 5), + + x86_reg_dreg =3D (12 << 5), + x86_reg_creg =3D (13 << 5), + x86_reg_sreg =3D (14 << 5), + x86_reg_sys =3D (15 << 5), +}; + +/* + * prefix byte + */ + +enum +{ + x86_pb_26 =3D 0x26, + x86_pb_2e =3D 0x2e, + x86_pb_36 =3D 0x36, + x86_pb_3e =3D 0x3e, + x86_pb_41 =3D 0x41, + x86_pb_42 =3D 0x42, + x86_pb_44 =3D 0x44, + x86_pb_48 =3D 0x48, + x86_pb_62 =3D 0x62, + x86_pb_64 =3D 0x64, + x86_pb_65 =3D 0x65, + x86_pb_66 =3D 0x66, + x86_pb_67 =3D 0x67, + x86_pb_9b =3D 0x9b, + x86_pb_c4 =3D 0xc4, + x86_pb_c5 =3D 0xc5, + x86_pb_d5 =3D 0xd5, + x86_pb_f0 =3D 0xf0, + x86_pb_f2 =3D 0xf2, + x86_pb_f3 =3D 0xf3, + + x86_pb_es =3D x86_pb_26, + x86_pb_cs =3D x86_pb_2e, /* branch not taken with Jcc */ + x86_pb_ss =3D x86_pb_36, + x86_pb_ds =3D x86_pb_3e, /* branch taken with Jcc (CET notrack) */ + x86_pb_rex_b =3D x86_pb_41, + x86_pb_rex_x =3D x86_pb_42, + x86_pb_rex_r =3D x86_pb_44, + x86_pb_rex_w =3D x86_pb_48, + x86_pb_evex =3D x86_pb_62, + x86_pb_fs =3D x86_pb_64, + x86_pb_gs =3D x86_pb_65, + x86_pb_osize =3D x86_pb_66, + x86_pb_asize =3D x86_pb_67, + x86_pb_wait =3D x86_pb_9b, /* x87 */ + x86_pb_vex3 =3D x86_pb_c4, + x86_pb_vex2 =3D x86_pb_c5, + x86_pb_rex2 =3D x86_pb_d5, + x86_pb_lock =3D x86_pb_f0, + x86_pb_repne =3D x86_pb_f2, /* REPNE/REPNZ and XACQUIRE */ + x86_pb_rep =3D x86_pb_f3, /* REP/REPE/REPZ and XRELEASE */ +}; + +/* + * mod values + */ + +enum +{ + x86_mod_disp0, + x86_mod_disp8, + x86_mod_dispw, + x86_mod_reg, +}; + +/* + * SIB scale + */ + +enum +{ + x86_scale_1, + x86_scale_2, + x86_scale_4, + x86_scale_8, +}; + +/* + * segment + */ + +enum +{ + x86_seg_none, + x86_seg_es, + x86_seg_cs, + x86_seg_ss, + x86_seg_ds, + x86_seg_fs, + x86_seg_gs +}; + +/* + * REX flags + */ + +enum +{ + x86_rex_b =3D 0x01, + x86_rex_x =3D 0x02, + x86_rex_r =3D 0x04, + x86_rex_w =3D 0x08, +}; + +/* + * VEX prefix + */ + +enum +{ + x86_pfx_none, + x86_pfx_66, + x86_pfx_f3, + x86_pfx_f2, + x86_pfx_9b, + x86_pfx_rexw =3D 8 +}; + +/* + * VEX map + */ + +enum +{ + x86_map_none, + x86_map_0f, + x86_map_0f38, + x86_map_0f3a, + x86_map_map4, + x86_map_map5, + x86_map_map6, +}; + +/* + * VEX length + */ + +enum +{ + x86_vex_l0 =3D 0, + x86_vex_l1 =3D 1, + x86_vex_l2 =3D 2, + x86_vex_l3 =3D 3, + x86_vex_lz =3D x86_vex_l0, + x86_vex_lig =3D x86_vex_l3, + x86_vex_l128 =3D x86_vex_l0, + x86_vex_l256 =3D x86_vex_l1, + x86_vex_l512 =3D x86_vex_l2, +}; + +/* + * VEX width + */ + +enum +{ + x86_vex_w0, + x86_vex_w1, +}; + +/* + * condition codes (x86) + */ + +enum +{ + x86_cc_o =3D 0, /* overflow */ + x86_cc_no =3D 1, /* no overflow */ + x86_cc_b =3D 2, /* below */ + x86_cc_c =3D 2, /* carry */ + x86_cc_nae =3D 2, /* neither-above-nor-equal */ + x86_cc_nb =3D 3, /* not-below */ + x86_cc_nc =3D 3, /* not-carry */ + x86_cc_ae =3D 3, /* above-or-equal */ + x86_cc_e =3D 4, /* equal */ + x86_cc_z =3D 4, /* zero */ + x86_cc_ne =3D 5, /* not-equal */ + x86_cc_nz =3D 5, /* not-zero */ + x86_cc_be =3D 6, /* below-or-equal */ + x86_cc_na =3D 6, /* not-above */ + x86_cc_nbe =3D 7, /* neither-below-nor-equal */ + x86_cc_a =3D 7, /* above */ + x86_cc_s =3D 8, /* sign */ + x86_cc_ns =3D 9, /* no-sign */ + x86_cc_p =3D 10, /* parity */ + x86_cc_pe =3D 10, /* parity-even */ + x86_cc_np =3D 11, /* no-parity */ + x86_cc_po =3D 11, /* parity-odd */ + x86_cc_l =3D 12, /* less */ + x86_cc_nge =3D 12, /* neither-greater-nor-equal */ + x86_cc_nl =3D 13, /* not-less */ + x86_cc_ge =3D 13, /* greater-or-equal */ + x86_cc_le =3D 14, /* less-or-equal */ + x86_cc_ng =3D 14, /* not-greater */ + x86_cc_nle =3D 15, /* neither-less-nor-equal- */ + x86_cc_g =3D 15, /* greater */ +}; + +/* + * condition codes (agnostic) + */ + +enum +{ + x86_o =3D 0, /* overflow (signed) */ + x86_no =3D 1, /* not-overflow (signed) */ + x86_c =3D 2, /* carry */ + x86_nc =3D 3, /* not-carry */ + x86_ltu =3D 2, /* less-than (unsigned) */ + x86_geu =3D 3, /* greater-than-or-equal (unsigned) */ + x86_eq =3D 4, /* equal */ + x86_ne =3D 5, /* not-equal */ + x86_leu =3D 6, /* less-than-or-equal (unsigned) */ + x86_gtu =3D 7, /* greater-than (unsigned) */ + x86_s =3D 8, /* sign */ + x86_ns =3D 9, /* not-sign */ + x86_lt =3D 12, /* less-than (signed) */ + x86_ge =3D 13, /* greater-than-or-equal (signed) */ + x86_le =3D 14, /* less-than-or-equal (signed) */ + x86_gt =3D 15, /* greater-than (signed) */ +}; + +/* + * compare packed operators + * + * oq =3D ordered queit, os =3D ordered signalling + * uq =3D unordered queit, us =3D unordered signalling + */ + +enum +{ + x86_eq_oq =3D 0x00, + x86_lt_os =3D 0x01, + x86_le_os =3D 0x02, + x86_unord_q =3D 0x03, + x86_neq_uq =3D 0x04, + x86_nlt_us =3D 0x05, + x86_nle_us =3D 0x06, + x86_ord_q =3D 0x07, + x86_eq_uq =3D 0x08, + x86_nge_us =3D 0x09, + x86_ngt_us =3D 0x0a, + x86_false_oq =3D 0x0b, + x86_neq_oq =3D 0x0c, + x86_ge_os =3D 0x0d, + x86_gt_os =3D 0x0e, + x86_true_uq =3D 0x0f, + x86_eq_os =3D 0x10, + x86_lt_oq =3D 0x11, + x86_le_oq =3D 0x12, + x86_unord_s =3D 0x13, + x86_neq_us =3D 0x14, + x86_nlt_uq =3D 0x15, + x86_nle_uq =3D 0x16, + x86_ord_s =3D 0x17, + x86_eq_us =3D 0x18, + x86_nge_uq =3D 0x19, + x86_ngt_uq =3D 0x1a, + x86_false_os =3D 0x1b, + x86_neq_os =3D 0x1c, + x86_ge_oq =3D 0x1d, + x86_gt_oq =3D 0x1e, + x86_true_us =3D 0x1f, +}; + +/* + * prefix encoding structures + */ + +/* + * ModRM struct + */ + +struct x86_modrm +{ + union { + uchar data[1]; + /* note: bitfield used for documentation purposes only */ + struct { + /* [0:2] */ uchar rm:3; + /* [3:5] */ uchar reg:3; + /* [6:7] */ uchar mod:2; + }; + }; +}; + +/* + * ModRM values + */ + +enum +{ + x86_rm_sp_sib =3D 4, + x86_rm_bp_disp0 =3D 5, + + x86_modrm_rm_mask =3D 7, + x86_modrm_reg_shift =3D 3, + x86_modrm_reg_mask =3D 7, + x86_modrm_mod_shift =3D 6, + x86_modrm_mod_mask =3D 3, +}; + +/* + * ModRM accessors + */ + +static inline uint x86_modrm_rm(uchar modrm) { + return modrm & x86_modrm_rm_mask; +} +static inline uint x86_modrm_reg(uchar modrm) { + return (modrm >> x86_modrm_reg_shift) & x86_modrm_reg_mask; +} +static inline uint x86_modrm_mod(uchar modrm) { + return (modrm >> x86_modrm_mod_shift) & x86_modrm_mod_mask; +} + +/* + * SIB struct + */ + +struct x86_sib +{ + union { + uchar data[1]; + /* note: bitfield used for documentation purposes only */ + struct { + /* [0:2] */ uchar b : 3; /* base[0:2] */ + /* [3:5] */ uchar x : 3; /* index[0:2] */ + /* [6:7] */ uchar s : 2; /* scale[0:2] */ + }; + }; +}; + +/* + * SIB values + */ + +enum { + x86_sib_b_mask =3D 7, + x86_sib_x_shift =3D 3, + x86_sib_x_mask =3D 7, + x86_sib_s_shift =3D 6, + x86_sib_s_mask =3D 3 +}; + +/* + * SIB accessors + */ + +static inline uint x86_sib_b(uchar sib) { + return sib & x86_sib_b_mask; +} +static inline uint x86_sib_x(uchar sib) { + return (sib >> x86_sib_x_shift) & x86_sib_x_mask; +} +static inline uint x86_sib_s(uchar sib) { + return (sib >> x86_sib_s_shift) & x86_sib_s_mask; +} + +/* + * REX struct + */ + +struct x86_rex +{ + union { + uchar data[1]; + /* note: bitfield used for documentation purposes only */ + struct { + /* [0] */ uchar b3 : 1; /* base[3] */ + /* [1] */ uchar x3 : 1; /* index[3] */ + /* [2] */ uchar r3 : 1; /* reg[3] */ + /* [3] */ uchar w : 1; /* width */ + }; + }; +}; + + +/* + * REX2 struct + */ + +struct x86_rex2 +{ + union { + uchar data[1]; + /* note: bitfield used for documentation purposes only */ + struct { + /* [0] */ uchar b3 : 1; /* base[3] */ + /* [1] */ uchar x3 : 1; /* index[3] */ + /* [2] */ uchar r3 : 1; /* reg[3] */ + /* [3] */ uchar w : 1; /* width */ + /* [4] */ uchar b4 : 1; /* base[4] */ + /* [5] */ uchar x4 : 1; /* index[4] */ + /* [6] */ uchar r4 : 1; /* reg[4] */ + /* [7] */ uchar m0 : 1; /* map prefix 0x0f */ + }; + }; +}; + + +/* + * VEX2 struct + */ + +struct x86_vex2 +{ + union { + uchar data[1]; + /* note: bitfield used for documentation purposes only */ + struct { + /* [0:1] */ uchar p : 2; /* see x86_pfx */ + /* [2] */ uchar l : 1; /* len 0=3D128 1=3D256 */ + /* [3:6] */ uchar vn : 4; /* ~vec[0:3] */ + /* [7] */ uchar r3n : 1; /* ~reg[3] */ + }; + }; +}; + +/* + * VEX3 struct + */ + +struct x86_vex3 +{ + union { + uchar data[2]; + /* note: bitfield used for documentation purposes only */ + struct { + /* [0:4] */ uchar m : 5; /* see x86_map */ + /* [5] */ uchar b3n : 1; /* ~base[3] */ + /* [6] */ uchar x3n : 1; /* ~index[3] */ + /* [7] */ uchar r3n : 1; /* ~reg[3] */ + + /* [0:1] */ uchar p : 2; /* see x86_pfx */ + /* [2] */ uchar l : 1; /* len 0=3D128 1=3D256 */ + /* [3:6] */ uchar vn : 4; /* ~vec[0:3] */ + /* [7] */ uchar w : 1; /* width */ + }; + }; +}; + +/* + * EVEX struct + */ + +struct x86_evex +{ + union { + uchar data[3]; + /* note: bitfield used for documentation purposes only */ + struct { + /* [0:2] */ uchar m : 3; /* see x86_map */ + /* [3] */ uchar b4 : 1; /* base[4] */ + /* [4] */ uchar r4n : 1; /* ~reg[4] */ + /* [5] */ uchar b3n : 1; /* ~base[3] */ + /* [6] */ uchar x3n : 1; /* ~index[3] */ + /* [7] */ uchar r3n : 1; /* ~reg[3] */ + + /* [0:1] */ uchar p : 2; /* see x86_pfx */ + /* [2] */ uchar x4n : 1; /* ~index[4] */ + /* [3:6] */ uchar vn : 4; /* ~vec[0:3] */ + /* [7] */ uchar w : 1; /* width */ + + /* [0:2] */ uchar a : 3; /* kmask[0:2] or map4.NF[2] no-flag= s */ + /* [3] */ uchar v4n : 1; /* ~vec[4] */ + /* [4] */ uchar br : 1; /* broadcast or map4.ND[4] new-dest= */ + /* [5:6] */ uchar l : 2; /* len 00=3D128 01=3D256, 10=3D512 = */ + /* [7] */ uchar z : 1; /* merge/zero */ + }; + }; +}; + +/* + * opcode encoding + */ + +enum +{ + x86_enc_w_shift =3D 0, + x86_enc_m_shift =3D x86_enc_w_shift + 3, + x86_enc_p_shift =3D x86_enc_m_shift + 3, + x86_enc_l_shift =3D x86_enc_p_shift + 4, + x86_enc_t_shift =3D x86_enc_l_shift + 3, + x86_enc_o_shift =3D x86_enc_t_shift + 2, + x86_enc_f_shift =3D x86_enc_o_shift + 1, + x86_enc_i_shift =3D x86_enc_f_shift + 3, + x86_enc_j_shift =3D x86_enc_i_shift + 3, + x86_enc_r_shift =3D x86_enc_j_shift + 2, + x86_enc_s_shift =3D x86_enc_r_shift + 3, + + x86_enc_w_w0 =3D (1 << x86_enc_w_shift), + x86_enc_w_w1 =3D (2 << x86_enc_w_shift), + x86_enc_w_wb =3D (3 << x86_enc_w_shift), + x86_enc_w_wn =3D (4 << x86_enc_w_shift), + x86_enc_w_wx =3D (5 << x86_enc_w_shift), + x86_enc_w_ww =3D (6 << x86_enc_w_shift), + x86_enc_w_wig =3D (7 << x86_enc_w_shift), + x86_enc_w_mask =3D (7 << x86_enc_w_shift), + + x86_enc_m_none =3D (0 << x86_enc_m_shift), + x86_enc_m_0f =3D (1 << x86_enc_m_shift), + x86_enc_m_0f38 =3D (2 << x86_enc_m_shift), + x86_enc_m_0f3a =3D (3 << x86_enc_m_shift), + x86_enc_m_map4 =3D (4 << x86_enc_m_shift), + x86_enc_m_map5 =3D (5 << x86_enc_m_shift), + x86_enc_m_map6 =3D (6 << x86_enc_m_shift), + x86_enc_m_mask =3D (7 << x86_enc_m_shift), + + x86_enc_p_none =3D (0 << x86_enc_p_shift), + x86_enc_p_66 =3D (1 << x86_enc_p_shift), + x86_enc_p_f3 =3D (2 << x86_enc_p_shift), + x86_enc_p_f2 =3D (3 << x86_enc_p_shift), + x86_enc_p_9b =3D (4 << x86_enc_p_shift), + x86_enc_p_rexw =3D (8 << x86_enc_p_shift), + x86_enc_p_mask =3D (7 << x86_enc_p_shift), + x86_enc_prexw_mask =3D (15 << x86_enc_p_shift), + + x86_enc_l_lz =3D (1 << x86_enc_l_shift), + x86_enc_l_l0 =3D (2 << x86_enc_l_shift), + x86_enc_l_l1 =3D (3 << x86_enc_l_shift), + x86_enc_l_128 =3D (4 << x86_enc_l_shift), + x86_enc_l_256 =3D (5 << x86_enc_l_shift), + x86_enc_l_512 =3D (6 << x86_enc_l_shift), + x86_enc_l_lig =3D (7 << x86_enc_l_shift), + x86_enc_l_mask =3D (7 << x86_enc_l_shift), + + x86_enc_t_none =3D (0 << x86_enc_t_shift), + x86_enc_t_lex =3D (1 << x86_enc_t_shift), + x86_enc_t_vex =3D (2 << x86_enc_t_shift), + x86_enc_t_evex =3D (3 << x86_enc_t_shift), + x86_enc_t_mask =3D (3 << x86_enc_t_shift), + + x86_enc_o_opcode_r =3D (1 << x86_enc_o_shift), /* XX+r */ + x86_enc_o_mask =3D (1 << x86_enc_o_shift), + + x86_enc_f_modrm_r =3D (1 << x86_enc_f_shift), /* /r */ + x86_enc_f_modrm_n =3D (2 << x86_enc_f_shift), /* /N */ + x86_enc_f_opcode =3D (3 << x86_enc_f_shift), /* XX */ + x86_enc_f_opcode_r =3D (4 << x86_enc_f_shift), /* XX+r */ + x86_enc_f_mask =3D (7 << x86_enc_f_shift), + + x86_enc_i_ib =3D (1 << x86_enc_i_shift), + x86_enc_i_iw =3D (2 << x86_enc_i_shift), + x86_enc_i_iwd =3D (3 << x86_enc_i_shift), + x86_enc_i_i16 =3D (4 << x86_enc_i_shift), + x86_enc_i_i32 =3D (5 << x86_enc_i_shift), + x86_enc_i_i64 =3D (6 << x86_enc_i_shift), + x86_enc_i_mask =3D (7 << x86_enc_i_shift), + + x86_enc_j_ib =3D (1 << x86_enc_j_shift), + x86_enc_j_i16 =3D (2 << x86_enc_j_shift), + x86_enc_j_mask =3D (3 << x86_enc_j_shift), + + x86_enc_r_rep =3D (1 << x86_enc_r_shift), + x86_enc_r_lock =3D (2 << x86_enc_r_shift), + x86_enc_r_norexb =3D (4 << x86_enc_r_shift), + x86_enc_r_mask =3D (7 << x86_enc_r_shift), + + x86_enc_s_o16 =3D (1 << x86_enc_s_shift), + x86_enc_s_o32 =3D (2 << x86_enc_s_shift), + x86_enc_s_o64 =3D (3 << x86_enc_s_shift), + x86_enc_s_a16 =3D (4 << x86_enc_s_shift), + x86_enc_s_a32 =3D (5 << x86_enc_s_shift), + x86_enc_s_a64 =3D (6 << x86_enc_s_shift), + x86_enc_s_mask =3D (7 << x86_enc_s_shift), + + x86_enc_immediate_mask =3D x86_enc_i_mask | x86_enc_j_mask, + x86_enc_suffix_mask =3D x86_enc_r_mask | x86_enc_s_mask, + x86_enc_param_mask =3D x86_enc_immediate_mask | x86_enc_suffix_m= ask +}; + +/* + * opcode encoding accessors + */ + +static inline uint x86_enc_width(uint enc) { + return enc & x86_enc_w_mask; +} +static inline uint x86_enc_prefix(uint enc) { + return enc & x86_enc_prexw_mask; +} +static inline uint x86_enc_length(uint enc) { + return enc & x86_enc_l_mask; +} +static inline uint x86_enc_opcode(uint enc) { + return enc & x86_enc_o_mask; +} +static inline uint x86_enc_func(uint enc) { + return enc & x86_enc_f_mask; +} +static inline uint x86_enc_map(uint enc) { + return enc & x86_enc_m_mask; +} +static inline uint x86_enc_imm(uint enc) { + return enc & x86_enc_i_mask; +} +static inline uint x86_enc_imm2(uint enc) { + return enc & x86_enc_j_mask; +} +static inline uint x86_enc_type(uint enc) { + return enc & x86_enc_t_mask; +} +static inline uint x86_enc_suffix(uint enc) { + return enc & x86_enc_suffix_mask; +} +static inline uint x86_enc_leading(uint enc) { + return enc & ~x86_enc_param_mask; +} +static inline uint x86_enc_has_rep(uint enc) { + return enc & x86_enc_r_rep; +} +static inline uint x86_enc_has_lock(uint enc) { + return enc & x86_enc_r_lock; +} +static inline uint x86_enc_has_norexb(uint enc) { + return enc & x86_enc_r_norexb; +} +static inline uint x86_enc_has_o16(uint enc) { + return (enc & x86_enc_s_mask) =3D=3D x86_enc_s_o16; +} +static inline uint x86_enc_has_o32(uint enc) { + return (enc & x86_enc_s_mask) =3D=3D x86_enc_s_o32; +} +static inline uint x86_enc_has_o64(uint enc) { + return (enc & x86_enc_s_mask) =3D=3D x86_enc_s_o64; +} +static inline uint x86_enc_has_a16(uint enc) { + return (enc & x86_enc_s_mask) =3D=3D x86_enc_s_a16; +} +static inline uint x86_enc_has_a32(uint enc) { + return (enc & x86_enc_s_mask) =3D=3D x86_enc_s_a32; +} +static inline uint x86_enc_has_a64(uint enc) { + return (enc & x86_enc_s_mask) =3D=3D x86_enc_s_a64; +} + +/* + * operand encoding + */ + +enum +{ + x86_opr_none, + + /* operand field shifts */ + x86_opr_ot =3D 8, + x86_opr_os =3D x86_opr_ot + 4, + x86_opr_ms =3D x86_opr_os + 4, + x86_opr_av =3D x86_opr_ms + 4, + x86_opr_et =3D x86_opr_av + 4, + x86_opr_ew =3D x86_opr_et + 2, + x86_opr_ec =3D x86_opr_ew + 3, + + x86_opr_ot_mask =3D (15 << x86_opr_ot), /* operand type */ + x86_opr_os_mask =3D (15 << x86_opr_os), /* operand size */ + x86_opr_ms_mask =3D (15 << x86_opr_ms), /* memory size */ + x86_opr_av_mask =3D (15 << x86_opr_av), /* auxiliary value */ + x86_opr_et_mask =3D (3 << x86_opr_et), /* element type */ + x86_opr_ew_mask =3D (7 << x86_opr_ew), /* element width */ + x86_opr_ec_mask =3D (7 << x86_opr_ec), /* element count */ + + /* operand flags */ + x86_opr_mem =3D (1 << 0), + x86_opr_ind =3D (1 << 1), + x86_opr_bcst =3D (1 << 2), + x86_opr_flag_er =3D (1 << 3), + x86_opr_flag_k =3D (1 << 4), + x86_opr_flag_sae =3D (1 << 5), + x86_opr_flag_z =3D (1 << 6), + x86_opr_flag_rs =3D (1 << 7), + + /* operand type */ + x86_opr_const =3D (1 << x86_opr_ot), /* constant */ + x86_opr_imm =3D (2 << x86_opr_ot), /* immediate */ + x86_opr_reg =3D (3 << x86_opr_ot), /* register */ + x86_opr_vec =3D (4 << x86_opr_ot), /* vector */ + x86_opr_mmx =3D (5 << x86_opr_ot), /* mmx */ + x86_opr_st =3D (6 << x86_opr_ot), /* x87 */ + x86_opr_k =3D (7 << x86_opr_ot), /* mask */ + x86_opr_seg =3D (8 << x86_opr_ot), /* segment */ + x86_opr_creg =3D (9 << x86_opr_ot), /* control */ + x86_opr_dreg =3D (10 << x86_opr_ot), /* debug */ + x86_opr_bnd =3D (11 << x86_opr_ot), /* bound */ + x86_opr_type_mask =3D x86_opr_ot_mask, + + /* operand sizes */ + x86_opr_size_8 =3D (1 << x86_opr_os), + x86_opr_size_16 =3D (2 << x86_opr_os), + x86_opr_size_32 =3D (3 << x86_opr_os), + x86_opr_size_64 =3D (4 << x86_opr_os), + x86_opr_size_128 =3D (5 << x86_opr_os), + x86_opr_size_256 =3D (6 << x86_opr_os), + x86_opr_size_512 =3D (7 << x86_opr_os), + x86_opr_size_1024 =3D (8 << x86_opr_os), + x86_opr_size_80 =3D (9 << x86_opr_os), + x86_opr_size_wd =3D (13 << x86_opr_os), + x86_opr_size_w =3D (14 << x86_opr_os), + x86_opr_size_a =3D (15 << x86_opr_os), + x86_opr_size_mask =3D x86_opr_os_mask, + + /* sized register */ + x86_opr_r8 =3D x86_opr_reg | x86_opr_size_8, + x86_opr_r16 =3D x86_opr_reg | x86_opr_size_16, + x86_opr_r32 =3D x86_opr_reg | x86_opr_size_32, + x86_opr_r64 =3D x86_opr_reg | x86_opr_size_64, + x86_opr_rw =3D x86_opr_reg | x86_opr_size_w, + x86_opr_ra =3D x86_opr_reg | x86_opr_size_a, + x86_opr_mm =3D x86_opr_vec | x86_opr_size_64, + x86_opr_xmm =3D x86_opr_vec | x86_opr_size_128, + x86_opr_ymm =3D x86_opr_vec | x86_opr_size_256, + x86_opr_zmm =3D x86_opr_vec | x86_opr_size_512, + + /* sized memory */ + x86_opr_m8 =3D x86_opr_mem | (1 << x86_opr_ms), /* byte = */ + x86_opr_m16 =3D x86_opr_mem | (2 << x86_opr_ms), /* word = */ + x86_opr_m32 =3D x86_opr_mem | (3 << x86_opr_ms), /* dword= */ + x86_opr_m64 =3D x86_opr_mem | (4 << x86_opr_ms), /* qword= */ + x86_opr_m128 =3D x86_opr_mem | (5 << x86_opr_ms), /* oword= /xmmword */ + x86_opr_m256 =3D x86_opr_mem | (6 << x86_opr_ms), /* ymmwo= rd */ + x86_opr_m512 =3D x86_opr_mem | (7 << x86_opr_ms), /* zmmwo= rd */ + x86_opr_m1024 =3D x86_opr_mem | (8 << x86_opr_ms), + x86_opr_m80 =3D x86_opr_mem | (9 << x86_opr_ms), /* tword= /tbyte */ + x86_opr_m384 =3D x86_opr_mem | (10 << x86_opr_ms), + x86_opr_mib =3D x86_opr_mem | (11 << x86_opr_ms), /* boun= d */ + x86_opr_vm32 =3D x86_opr_mem | (12 << x86_opr_ms), /* vecm= em32 */ + x86_opr_vm64 =3D x86_opr_mem | (13 << x86_opr_ms), /* vecm= em64 */ + x86_opr_mw =3D x86_opr_mem | (14 << x86_opr_ms), /* 16/3= 2/64 */ + x86_opr_mp =3D x86_opr_mem | (15 << x86_opr_ms), /* poin= ter */ + x86_opr_mem_mask =3D x86_opr_mem | (15 << x86_opr_ms), + + /* unsized register / sized memory */ + x86_opr_r_m8 =3D x86_opr_reg | x86_opr_m8, + x86_opr_r_m16 =3D x86_opr_reg | x86_opr_m16, + x86_opr_r_m32 =3D x86_opr_reg | x86_opr_m32, + x86_opr_r_m64 =3D x86_opr_reg | x86_opr_m64, + + /* sized register / sized memory */ + x86_opr_r8_m8 =3D x86_opr_r8 | x86_opr_m8, + x86_opr_r16_m8 =3D x86_opr_r16 | x86_opr_m8, + x86_opr_r16_m16 =3D x86_opr_r16 | x86_opr_m16, + x86_opr_r32_m8 =3D x86_opr_r32 | x86_opr_m8, + x86_opr_r32_m16 =3D x86_opr_r32 | x86_opr_m16, + x86_opr_r32_m32 =3D x86_opr_r32 | x86_opr_m32, + x86_opr_r64_m8 =3D x86_opr_r64 | x86_opr_m8, + x86_opr_r64_m16 =3D x86_opr_r64 | x86_opr_m16, + x86_opr_r64_m32 =3D x86_opr_r64 | x86_opr_m32, + x86_opr_r64_m64 =3D x86_opr_r64 | x86_opr_m64, + x86_opr_rw_mw =3D x86_opr_rw | x86_opr_mw, + + /* sized vector / sized memory */ + x86_opr_mm_m32 =3D x86_opr_mm | x86_opr_m32, + x86_opr_mm_m64 =3D x86_opr_mm | x86_opr_m64, + x86_opr_xmm_m8 =3D x86_opr_xmm | x86_opr_m8, + x86_opr_xmm_m16 =3D x86_opr_xmm | x86_opr_m16, + x86_opr_xmm_m32 =3D x86_opr_xmm | x86_opr_m32, + x86_opr_xmm_m64 =3D x86_opr_xmm | x86_opr_m64, + x86_opr_xmm_m128 =3D x86_opr_xmm | x86_opr_m128, + x86_opr_ymm_m256 =3D x86_opr_ymm | x86_opr_m256, + x86_opr_zmm_m512 =3D x86_opr_zmm | x86_opr_m512, + + /* sized vector memory */ + x86_opr_vm32x =3D x86_opr_xmm | x86_opr_vm32, + x86_opr_vm32y =3D x86_opr_ymm | x86_opr_vm32, + x86_opr_vm32z =3D x86_opr_zmm | x86_opr_vm32, + x86_opr_vm64x =3D x86_opr_xmm | x86_opr_vm64, + x86_opr_vm64y =3D x86_opr_ymm | x86_opr_vm64, + x86_opr_vm64z =3D x86_opr_zmm | x86_opr_vm64, + + /* mask / sized memory */ + x86_opr_k_m8 =3D x86_opr_k | x86_opr_m8, + x86_opr_k_m16 =3D x86_opr_k | x86_opr_m16, + x86_opr_k_m32 =3D x86_opr_k | x86_opr_m32, + x86_opr_k_m64 =3D x86_opr_k | x86_opr_m64, + + /* bound / memory */ + x86_opr_bnd_mem =3D x86_opr_bnd | x86_opr_mem, + + /* memory operand alias */ + x86_opr_m16int =3D x86_opr_m16, + x86_opr_m32fp =3D x86_opr_m32, + x86_opr_m32int =3D x86_opr_m32, + x86_opr_m64fp =3D x86_opr_m64, + x86_opr_m64int =3D x86_opr_m64, + x86_opr_m80bcd =3D x86_opr_m80, + x86_opr_m80dec =3D x86_opr_m80, + x86_opr_m80fp =3D x86_opr_m80, + + /* sized immediate */ + x86_opr_ib =3D x86_opr_imm | x86_opr_size_8, + x86_opr_i16 =3D x86_opr_imm | x86_opr_size_16, + x86_opr_i32 =3D x86_opr_imm | x86_opr_size_32, + x86_opr_i64 =3D x86_opr_imm | x86_opr_size_64, + x86_opr_iwd =3D x86_opr_imm | x86_opr_size_wd, + x86_opr_iw =3D x86_opr_imm | x86_opr_size_w, + + /* memory offset */ + x86_opr_moffs =3D x86_opr_imm | x86_opr_mem | x86_opr_size_= w, + + /* constant */ + x86_opr_1 =3D x86_opr_const | (1 << x86_opr_av), + + /* registers sequential */ + x86_opr_flag_rs2 =3D x86_opr_flag_rs | (1 << x86_opr_av), + x86_opr_flag_rs4 =3D x86_opr_flag_rs | (2 << x86_opr_av), + + /* sized broadcast */ + x86_opr_m16bcst =3D x86_opr_bcst | (1 << x86_opr_av), + x86_opr_m32bcst =3D x86_opr_bcst | (2 << x86_opr_av), + x86_opr_m64bcst =3D x86_opr_bcst | (3 << x86_opr_av), + x86_opr_bcst_mask =3D x86_opr_bcst | x86_opr_av_mask, + + /* sized vector / sized memory / broadcast */ + x86_opr_xmm_m32_m16bcst =3D x86_opr_mm_m32 | x86_opr_m16bcst, + x86_opr_xmm_m64_m16bcst =3D x86_opr_xmm_m64 | x86_opr_m16bcst, + x86_opr_xmm_m64_m32bcst =3D x86_opr_xmm_m64 | x86_opr_m32bcst, + x86_opr_xmm_m128_m16bcst =3D x86_opr_xmm_m128 | x86_opr_m16bcst, + x86_opr_xmm_m128_m32bcst =3D x86_opr_xmm_m128 | x86_opr_m32bcst, + x86_opr_xmm_m128_m64bcst =3D x86_opr_xmm_m128 | x86_opr_m64bcst, + x86_opr_ymm_m256_m16bcst =3D x86_opr_ymm_m256 | x86_opr_m16bcst, + x86_opr_ymm_m256_m32bcst =3D x86_opr_ymm_m256 | x86_opr_m32bcst, + x86_opr_ymm_m256_m64bcst =3D x86_opr_ymm_m256 | x86_opr_m64bcst, + x86_opr_zmm_m512_m16bcst =3D x86_opr_zmm_m512 | x86_opr_m16bcst, + x86_opr_zmm_m512_m32bcst =3D x86_opr_zmm_m512 | x86_opr_m32bcst, + x86_opr_zmm_m512_m64bcst =3D x86_opr_zmm_m512 | x86_opr_m64bcst, + + /* relative displacement */ + x86_opr_rel8 =3D x86_opr_imm | x86_opr_ind | x86_opr_size_= 8, + x86_opr_relw =3D x86_opr_imm | x86_opr_ind | x86_opr_size_= w, + + /* enter / far displacement */ + x86_opr_far16_16 =3D x86_opr_imm | x86_opr_ind | (1 << x86_opr= _av), + x86_opr_far16_32 =3D x86_opr_imm | x86_opr_ind | (2 << x86_opr= _av), + + /* far memory indirect */ + x86_opr_memfar16_16 =3D x86_opr_mem | x86_opr_ind | (3 << x86_opr= _av), + x86_opr_memfar16_32 =3D x86_opr_mem | x86_opr_ind | (4 << x86_opr= _av), + x86_opr_memfar16_64 =3D x86_opr_mem | x86_opr_ind | (5 << x86_opr= _av), + + /* implicit register */ + x86_opr_reg_a =3D x86_opr_reg | x86_opr_ind | (1 << x86_opr= _av), + x86_opr_reg_c =3D x86_opr_reg | x86_opr_ind | (2 << x86_opr= _av), + x86_opr_reg_d =3D x86_opr_reg | x86_opr_ind | (3 << x86_opr= _av), + x86_opr_reg_b =3D x86_opr_reg | x86_opr_ind | (4 << x86_opr= _av), + x86_opr_reg_si =3D x86_opr_reg | x86_opr_ind | (5 << x86_opr= _av), + x86_opr_reg_di =3D x86_opr_reg | x86_opr_ind | (6 << x86_opr= _av), + x86_opr_reg_ah =3D x86_opr_reg | x86_opr_ind | (7 << x86_opr= _av), + x86_opr_reg_v0 =3D x86_opr_vec | x86_opr_ind | (1 << x86_opr= _av), + x86_opr_reg_st0 =3D x86_opr_st | x86_opr_ind | (1 << x86_opr= _av), + x86_opr_seg_es =3D x86_opr_seg | x86_opr_ind | (1 << x86_opr= _av), + x86_opr_seg_cs =3D x86_opr_seg | x86_opr_ind | (2 << x86_opr= _av), + x86_opr_seg_ss =3D x86_opr_seg | x86_opr_ind | (3 << x86_opr= _av), + x86_opr_seg_ds =3D x86_opr_seg | x86_opr_ind | (4 << x86_opr= _av), + x86_opr_seg_fs =3D x86_opr_seg | x86_opr_ind | (5 << x86_opr= _av), + x86_opr_seg_gs =3D x86_opr_seg | x86_opr_ind | (6 << x86_opr= _av), + + /* sized implicit register */ + x86_opr_reg_al =3D x86_opr_reg_a | x86_opr_size_8, + x86_opr_reg_cl =3D x86_opr_reg_c | x86_opr_size_8, + x86_opr_reg_ax =3D x86_opr_reg_a | x86_opr_size_16, + x86_opr_reg_cx =3D x86_opr_reg_c | x86_opr_size_16, + x86_opr_reg_dx =3D x86_opr_reg_d | x86_opr_size_16, + x86_opr_reg_bx =3D x86_opr_reg_b | x86_opr_size_16, + x86_opr_reg_eax =3D x86_opr_reg_a | x86_opr_size_32, + x86_opr_reg_ecx =3D x86_opr_reg_c | x86_opr_size_32, + x86_opr_reg_edx =3D x86_opr_reg_d | x86_opr_size_32, + x86_opr_reg_ebx =3D x86_opr_reg_b | x86_opr_size_32, + x86_opr_reg_rax =3D x86_opr_reg_a | x86_opr_size_64, + x86_opr_reg_rcx =3D x86_opr_reg_c | x86_opr_size_64, + x86_opr_reg_rdx =3D x86_opr_reg_d | x86_opr_size_64, + x86_opr_reg_rbx =3D x86_opr_reg_b | x86_opr_size_64, + x86_opr_reg_aw =3D x86_opr_reg_a | x86_opr_size_w, + x86_opr_reg_cw =3D x86_opr_reg_c | x86_opr_size_w, + x86_opr_reg_dw =3D x86_opr_reg_d | x86_opr_size_w, + x86_opr_reg_bw =3D x86_opr_reg_b | x86_opr_size_w, + x86_opr_reg_pa =3D x86_opr_reg_a | x86_opr_size_a, + x86_opr_reg_pc =3D x86_opr_reg_c | x86_opr_size_a, + x86_opr_reg_pd =3D x86_opr_reg_d | x86_opr_size_a, + x86_opr_reg_pb =3D x86_opr_reg_b | x86_opr_size_a, + x86_opr_reg_psi =3D x86_opr_reg_si | x86_opr_size_a, + x86_opr_reg_pdi =3D x86_opr_reg_di | x86_opr_size_a, + x86_opr_reg_xmm0 =3D x86_opr_reg_v0 | x86_opr_size_128, + x86_opr_reg_xmm0_7 =3D x86_opr_reg_v0 | x86_opr_size_1024, + + /* element type */ + x86_opr_et_none =3D (0 << x86_opr_et), + x86_opr_et_i =3D (1 << x86_opr_et), + x86_opr_et_f =3D (2 << x86_opr_et), + x86_opr_et_bf =3D (3 << x86_opr_et), + + /* element width */ + x86_opr_ew_8 =3D (1 << x86_opr_ew), + x86_opr_ew_16 =3D (2 << x86_opr_ew), + x86_opr_ew_32 =3D (3 << x86_opr_ew), + x86_opr_ew_64 =3D (4 << x86_opr_ew), + x86_opr_ew_128 =3D (5 << x86_opr_ew), + x86_opr_ew_256 =3D (6 << x86_opr_ew), + x86_opr_ew_512 =3D (7 << x86_opr_ew), + + /* element count */ + x86_opr_ec_x1 =3D (1 << x86_opr_ec), + x86_opr_ec_x2 =3D (2 << x86_opr_ec), + x86_opr_ec_x4 =3D (3 << x86_opr_ec), + x86_opr_ec_x8 =3D (4 << x86_opr_ec), + x86_opr_ec_x16 =3D (5 << x86_opr_ec), + x86_opr_ec_x32 =3D (6 << x86_opr_ec), + x86_opr_ec_x64 =3D (7 << x86_opr_ec), + + /* tuple type */ + x86_opr_i8x1 =3D x86_opr_et_i | x86_opr_ew_8 | x86_opr_ec_= x1, + x86_opr_i8x2 =3D x86_opr_et_i | x86_opr_ew_8 | x86_opr_ec_= x2, + x86_opr_i8x4 =3D x86_opr_et_i | x86_opr_ew_8 | x86_opr_ec_= x4, + x86_opr_i8x8 =3D x86_opr_et_i | x86_opr_ew_8 | x86_opr_ec_= x8, + x86_opr_i8x16 =3D x86_opr_et_i | x86_opr_ew_8 | x86_opr_ec_= x16, + x86_opr_i8x32 =3D x86_opr_et_i | x86_opr_ew_8 | x86_opr_ec_= x32, + x86_opr_i8x64 =3D x86_opr_et_i | x86_opr_ew_8 | x86_opr_ec_= x64, + x86_opr_i16x1 =3D x86_opr_et_i | x86_opr_ew_16 | x86_opr_ec= _x1, + x86_opr_i16x2 =3D x86_opr_et_i | x86_opr_ew_16 | x86_opr_ec= _x2, + x86_opr_i16x4 =3D x86_opr_et_i | x86_opr_ew_16 | x86_opr_ec= _x4, + x86_opr_i16x8 =3D x86_opr_et_i | x86_opr_ew_16 | x86_opr_ec= _x8, + x86_opr_i16x16 =3D x86_opr_et_i | x86_opr_ew_16 | x86_opr_ec= _x16, + x86_opr_i16x32 =3D x86_opr_et_i | x86_opr_ew_16 | x86_opr_ec= _x32, + x86_opr_i32x1 =3D x86_opr_et_i | x86_opr_ew_32 | x86_opr_ec= _x1, + x86_opr_i32x2 =3D x86_opr_et_i | x86_opr_ew_32 | x86_opr_ec= _x2, + x86_opr_i32x4 =3D x86_opr_et_i | x86_opr_ew_32 | x86_opr_ec= _x4, + x86_opr_i32x8 =3D x86_opr_et_i | x86_opr_ew_32 | x86_opr_ec= _x8, + x86_opr_i32x16 =3D x86_opr_et_i | x86_opr_ew_32 | x86_opr_ec= _x16, + x86_opr_i64x1 =3D x86_opr_et_i | x86_opr_ew_64 | x86_opr_ec= _x1, + x86_opr_i64x2 =3D x86_opr_et_i | x86_opr_ew_64 | x86_opr_ec= _x2, + x86_opr_i64x4 =3D x86_opr_et_i | x86_opr_ew_64 | x86_opr_ec= _x4, + x86_opr_i64x8 =3D x86_opr_et_i | x86_opr_ew_64 | x86_opr_ec= _x8, + x86_opr_i128x1 =3D x86_opr_et_i | x86_opr_ew_128 | x86_opr_e= c_x1, + x86_opr_i128x2 =3D x86_opr_et_i | x86_opr_ew_128 | x86_opr_e= c_x2, + x86_opr_i128x4 =3D x86_opr_et_i | x86_opr_ew_128 | x86_opr_e= c_x4, + x86_opr_i256x1 =3D x86_opr_et_i | x86_opr_ew_256 | x86_opr_e= c_x1, + x86_opr_i256x2 =3D x86_opr_et_i | x86_opr_ew_256 | x86_opr_e= c_x2, + x86_opr_i512x1 =3D x86_opr_et_i | x86_opr_ew_512 | x86_opr_e= c_x1, + x86_opr_f8x1 =3D x86_opr_et_f | x86_opr_ew_8 | x86_opr_ec_= x1, + x86_opr_f8x2 =3D x86_opr_et_f | x86_opr_ew_8 | x86_opr_ec_= x2, + x86_opr_f8x4 =3D x86_opr_et_f | x86_opr_ew_8 | x86_opr_ec_= x4, + x86_opr_f8x8 =3D x86_opr_et_f | x86_opr_ew_8 | x86_opr_ec_= x8, + x86_opr_f8x16 =3D x86_opr_et_f | x86_opr_ew_8 | x86_opr_ec_= x16, + x86_opr_f8x32 =3D x86_opr_et_f | x86_opr_ew_8 | x86_opr_ec_= x32, + x86_opr_f8x64 =3D x86_opr_et_f | x86_opr_ew_8 | x86_opr_ec_= x64, + x86_opr_f16x1 =3D x86_opr_et_f | x86_opr_ew_16 | x86_opr_ec= _x1, + x86_opr_f16x2 =3D x86_opr_et_f | x86_opr_ew_16 | x86_opr_ec= _x2, + x86_opr_f16x4 =3D x86_opr_et_f | x86_opr_ew_16 | x86_opr_ec= _x4, + x86_opr_f16x8 =3D x86_opr_et_f | x86_opr_ew_16 | x86_opr_ec= _x8, + x86_opr_f16x16 =3D x86_opr_et_f | x86_opr_ew_16 | x86_opr_ec= _x16, + x86_opr_f16x32 =3D x86_opr_et_f | x86_opr_ew_16 | x86_opr_ec= _x32, + x86_opr_f32x1 =3D x86_opr_et_f | x86_opr_ew_32 | x86_opr_ec= _x1, + x86_opr_f32x2 =3D x86_opr_et_f | x86_opr_ew_32 | x86_opr_ec= _x2, + x86_opr_f32x4 =3D x86_opr_et_f | x86_opr_ew_32 | x86_opr_ec= _x4, + x86_opr_f32x8 =3D x86_opr_et_f | x86_opr_ew_32 | x86_opr_ec= _x8, + x86_opr_f32x16 =3D x86_opr_et_f | x86_opr_ew_32 | x86_opr_ec= _x16, + x86_opr_f64x1 =3D x86_opr_et_f | x86_opr_ew_64 | x86_opr_ec= _x1, + x86_opr_f64x2 =3D x86_opr_et_f | x86_opr_ew_64 | x86_opr_ec= _x2, + x86_opr_f64x4 =3D x86_opr_et_f | x86_opr_ew_64 | x86_opr_ec= _x4, + x86_opr_f64x8 =3D x86_opr_et_f | x86_opr_ew_64 | x86_opr_ec= _x8, +}; + +/* + * operand encoding accessors + */ + +static inline uint x86_opr_has_mem(uint opr) { + return (opr & x86_opr_mem) !=3D 0; +} +static inline uint x86_opr_type_val(uint opr) { + return opr & x86_opr_type_mask; +} +static inline uint x86_opr_size_val(uint opr) { + return opr & x86_opr_size_mask; +} +static inline uint x86_opr_mem_val(uint opr) { + return opr & x86_opr_mem_mask; +} +static inline uint x86_opr_bcst_val(uint opr) { + return opr & x86_opr_bcst_mask; +} +static inline uint x86_opr_et_val(uint opr) { + return opr & x86_opr_et_mask; +} +static inline uint x86_opr_ec_val(uint opr) { + return opr & x86_opr_ec_mask; +} +static inline uint x86_opr_ew_val(uint opr) { + return opr & x86_opr_ew_mask; +} + +static inline uint x86_opr_mem_size(uint opr) +{ + switch (x86_opr_mem_val(opr)) { + case x86_opr_m8: return x86_opr_size_8; + case x86_opr_m16: return x86_opr_size_16; + case x86_opr_m32: return x86_opr_size_32; + case x86_opr_m64: return x86_opr_size_64; + case x86_opr_m80: return x86_opr_size_80; + case x86_opr_m128: return x86_opr_size_128; + case x86_opr_m256: return x86_opr_size_256; + case x86_opr_m512: return x86_opr_size_512; + case x86_opr_mw: + default: return x86_opr_size_w; + } +} + +static inline uint x86_opr_ew_bytes(uint opr) +{ + switch (x86_opr_ew_val(opr)) { + case x86_opr_ew_8: return 1; + case x86_opr_ew_16: return 2; + case x86_opr_ew_32: return 4; + case x86_opr_ew_64: return 8; + case x86_opr_ew_128: return 16; + case x86_opr_ew_256: return 32; + case x86_opr_ew_512: return 64; + } + return 0; +} + +static inline uint x86_opr_ew_size(uint opr) +{ + switch (x86_opr_ew_val(opr)) { + case x86_opr_ew_8: return x86_opr_size_8; + case x86_opr_ew_16: return x86_opr_size_16; + case x86_opr_ew_32: return x86_opr_size_32; + case x86_opr_ew_64: return x86_opr_size_64; + case x86_opr_ew_128: return x86_opr_size_128; + case x86_opr_ew_256: return x86_opr_size_256; + case x86_opr_ew_512: return x86_opr_size_512; + } + return 0; +} + +static inline uint x86_opr_ec_mult(uint opr) +{ + switch (x86_opr_ec_val(opr)) { + case x86_opr_ec_x1: return 1; + case x86_opr_ec_x2: return 2; + case x86_opr_ec_x4: return 4; + case x86_opr_ec_x8: return 8; + case x86_opr_ec_x16: return 16; + case x86_opr_ec_x32: return 32; + case x86_opr_ec_x64: return 64; + } + return 0; +} + +/* + * order encoding + */ + +enum +{ + x86_ord_none, + + x86_ord_s1 =3D 0, + x86_ord_s2 =3D x86_ord_s1 + 3, + x86_ord_s3 =3D x86_ord_s2 + 3, + + x86_ord_const =3D (1 << x86_ord_s1), /* - */ + x86_ord_imm =3D (2 << x86_ord_s1), /* I */ + x86_ord_reg =3D (3 << x86_ord_s1), /* R */ + x86_ord_mrm =3D (4 << x86_ord_s1), /* M */ + x86_ord_vec =3D (5 << x86_ord_s1), /* V */ + x86_ord_opr =3D (6 << x86_ord_s1), /* O */ + x86_ord_type_mask =3D (7 << x86_ord_s1), + + x86_ord_r =3D (1 << x86_ord_s2), + x86_ord_w =3D (2 << x86_ord_s2), + x86_ord_rw =3D (3 << x86_ord_s2), + x86_ord_i =3D (4 << x86_ord_s2), + x86_ord_ri =3D (5 << x86_ord_s2), + x86_ord_wi =3D (6 << x86_ord_s2), + x86_ord_rwi =3D (7 << x86_ord_s2), + x86_ord_flag_mask =3D (7 << x86_ord_s2), + + x86_ord_one =3D x86_ord_const | (1 << x86_ord_s3), + x86_ord_rax =3D x86_ord_const | (2 << x86_ord_s3), + x86_ord_rcx =3D x86_ord_const | (3 << x86_ord_s3), + x86_ord_rdx =3D x86_ord_const | (4 << x86_ord_s3), + x86_ord_rbx =3D x86_ord_const | (5 << x86_ord_s3), + x86_ord_rsp =3D x86_ord_const | (6 << x86_ord_s3), + x86_ord_rbp =3D x86_ord_const | (7 << x86_ord_s3), + x86_ord_rsi =3D x86_ord_const | (8 << x86_ord_s3), + x86_ord_rdi =3D x86_ord_const | (9 << x86_ord_s3), + x86_ord_st0 =3D x86_ord_const | (10 << x86_ord_s3), + x86_ord_stx =3D x86_ord_const | (11 << x86_ord_s3), + x86_ord_seg =3D x86_ord_const | (12 << x86_ord_s3), + x86_ord_xmm0 =3D x86_ord_const | (13 << x86_ord_s3), + x86_ord_xmm0_7 =3D x86_ord_const | (14 << x86_ord_s3), + x86_ord_mxcsr =3D x86_ord_const | (15 << x86_ord_s3), + x86_ord_rflags =3D x86_ord_const | (16 << x86_ord_s3), + + x86_ord_sib =3D x86_ord_mrm | (1 << x86_ord_s3), + + x86_ord_is4 =3D x86_ord_imm | (1 << x86_ord_s3), + x86_ord_ime =3D x86_ord_imm | (2 << x86_ord_s3), +}; + +/* + * order encoding accessors + */ + +static inline uint x86_ord_type_val(uint ord) { + return ord & x86_ord_type_mask; +} + +/* + * codec flags + */ + +enum +{ + x86_ce_shift =3D 0, + x86_cm_shift =3D 3, + x86_ci_shift =3D 5, + x86_cj_shift =3D 8, + + /* [0:2] encoding */ + x86_ce_none =3D (0 << x86_ce_shift), + x86_ce_rex =3D (1 << x86_ce_shift), + x86_ce_rex2 =3D (2 << x86_ce_shift), + x86_ce_vex2 =3D (3 << x86_ce_shift), + x86_ce_vex3 =3D (4 << x86_ce_shift), + x86_ce_evex =3D (5 << x86_ce_shift), + x86_ce_mask =3D (7 << x86_ce_shift), + + /* [3:4] map */ + x86_cm_none =3D (0 << x86_cm_shift), + x86_cm_0f =3D (1 << x86_cm_shift), + x86_cm_0f38 =3D (2 << x86_cm_shift), + x86_cm_0f3a =3D (3 << x86_cm_shift), + x86_cm_mask =3D (3 << x86_cm_shift), + + /* [5:7] imm */ + x86_ci_none =3D (0 << x86_ci_shift), + x86_ci_ib =3D (1 << x86_ci_shift), + x86_ci_iw =3D (2 << x86_ci_shift), + x86_ci_iwd =3D (3 << x86_ci_shift), + x86_ci_i16 =3D (4 << x86_ci_shift), + x86_ci_i32 =3D (5 << x86_ci_shift), + x86_ci_i64 =3D (6 << x86_ci_shift), + x86_ci_mask =3D (7 << x86_ci_shift), + + /* [8:9] imm2 */ + x86_cj_ib =3D (1 << x86_cj_shift), + x86_cj_i16 =3D (2 << x86_cj_shift), + x86_cj_mask =3D (3 << x86_cj_shift), + + /* [10:15] prefixes */ + x86_cp_osize =3D (1 << 10), /* 0x66 */ + x86_cp_asize =3D (1 << 11), /* 0x67 */ + x86_cp_wait =3D (1 << 12), /* 0x9B */ + x86_cp_lock =3D (1 << 13), /* 0xF0 */ + x86_cp_repne =3D (1 << 14), /* 0xF2 */ + x86_cp_rep =3D (1 << 15), /* 0xF3 */ + + /* [16:18] flags */ + x86_cf_modrm =3D (1 << 16), + x86_cf_ia32 =3D (1 << 17), + x86_cf_amd64 =3D (1 << 18), +}; + +/* + * codec struct + */ + +struct x86_codec +{ + union { + x86_rex rex; + x86_rex2 rex2; + x86_vex2 vex2; + x86_vex3 vex3; + x86_evex evex; + }; + + union { + uchar opc[2]; + struct { + uchar opc0; + x86_modrm modrm; + }; + }; + + uchar opclen : 2; + uchar seg : 3; + uchar spare; + x86_sib sib; + + uint flags; + ushort rec; + short imm2; + + union { + struct { + int disp32; + int imm32; + }; + struct { + ullong imm64; + }; + }; +}; + +/* + * codec accessors + */ + +static inline int x86_codec_field_ce(x86_codec *c) { + return c->flags & x86_ce_mask; +} +static inline int x86_codec_field_cm(x86_codec *c) { + return c->flags & x86_cm_mask; +} +static inline int x86_codec_field_ci(x86_codec *c) { + return c->flags & x86_ci_mask; +} +static inline int x86_codec_field_cj(x86_codec *c) { + return c->flags & x86_cj_mask; +} +static inline int x86_codec_has_wait(x86_codec *c) { + return (c->flags & x86_cp_wait) !=3D 0; +} +static inline int x86_codec_has_lock(x86_codec *c) { + return (c->flags & x86_cp_lock) !=3D 0; +} +static inline int x86_codec_has_rep(x86_codec *c) { + return (c->flags & x86_cp_rep) !=3D 0; +} +static inline int x86_codec_has_repne(x86_codec *c) { + return (c->flags & x86_cp_repne) !=3D 0; +} +static inline int x86_codec_has_osize(x86_codec *c) { + return (c->flags & x86_cp_osize) !=3D 0; +} +static inline int x86_codec_has_asize(x86_codec *c) { + return (c->flags & x86_cp_asize) !=3D 0; +} +static inline int x86_codec_has_modrm(x86_codec *c) { + return (c->flags & x86_cf_modrm) !=3D 0; +} +static inline int x86_codec_is16(x86_codec *c) { + return (c->flags & (x86_cf_ia32 | x86_cf_amd64)) =3D=3D 0; +} +static inline int x86_codec_is32(x86_codec *c) { + return (c->flags & x86_cf_ia32) !=3D 0; +} +static inline int x86_codec_is64(x86_codec *c) { + return (c->flags & x86_cf_amd64) !=3D 0; +} + +/* + * modes + */ + +enum +{ + x86_modes_16 =3D (1 << 0), + x86_modes_32 =3D (1 << 1), + x86_modes_64 =3D (1 << 2), +}; + +/* + * modes accessors + */ + +static inline int x86_mode_has16(uint mode) { + return (mode & x86_modes_16) !=3D 0; +} +static inline int x86_mode_has32(uint mode) { + return (mode & x86_modes_32) !=3D 0; +} +static inline int x86_mode_has64(uint mode) { + return (mode & x86_modes_64) !=3D 0; +} + +/* + * memory operand + */ + +struct x86_mem +{ + union { + uint code; + struct { + uint base : 9; + uint index : 9; + uint scale : 2; + }; + }; + int disp; +}; + +/* + * opcode metadata + * + * type, prefix, map, opcode, mask, plus operand and order records. + * + * opcode - opcode number from opcode enum for name lookup + * mode - operating mode (16 | 32 | 64) + * opr - operand list (r8/m8, rw/mw, xmm/m128, etc) + * ord - operand order (register, immediate, regmem, etc) + * enc - operand encoding (type, width, prefix, map, immediate, etc) + * opc - opcode, ModRM function byte or second opcode byte. + * opm - opcode mask (f8 for XX+r), ModRM function or second byte mask. + * + * prefix and map are provisioned as 6 bits each to align the bitfield. + * there are 3 types, 10 prefixes (5 * 2), and 7 maps (up to map6). + */ + +struct x86_opc_data +{ + ushort op; + ushort mode; + ushort opr; + ushort ord; + uint enc; + union { + uchar opc[2]; + ushort opc_s; + }; + union { + uchar opm[2]; + ushort opm_s; + }; +}; + +struct x86_opr_data +{ + uint opr[4]; +}; + +struct x86_ord_data +{ + ushort ord[4]; +}; + +/* + * ModRM encoder + */ + +static inline x86_modrm x86_enc_modrm(uint mod, uint reg, uint rm) +{ + x86_modrm modrm =3D { + .data =3D { + /* [0:2] */ (rm & 7u) | + /* [3:5] */ ((reg & 7u) << 3) | + /* [6:7] */ ((mod & 3u) << 6) + } + }; + return modrm; +} + +/* + * SIB encoder + */ + +static inline x86_sib x86_enc_sib(uint s, uint x, uint b) +{ + x86_sib sib =3D { + .data =3D { + /* [0:2] */ (b & 7u) | + /* [3:5] */ ((x & 7u) << 3) | + /* [6:7] */ (((uint)s & 3u) << 6) + } + }; + return sib; +} + +/* + * REX encoder + */ + +static inline x86_rex x86_enc_rex(uint w, uint r, uint x, uint b) +{ + x86_rex rex =3D { + .data =3D { + /* [0] */ ((b & 8u) >> 3) | + /* [1] */ ((x & 8u) >> 2) | + /* [2] */ ((r & 8u) >> 1) | + /* [3] */ ((w & 1u) << 3) | + /* [4:7] */ 0x40 + } + }; + return rex; +} + +/* + * REX2 encoder + */ + +static inline x86_rex2 x86_enc_rex2(uint m, uint w, uint r, uint x, uint b) +{ + x86_rex2 rex2 =3D { + .data =3D { + /* [0] */ ((b & 8u) >> 3) | + /* [1] */ ((x & 8u) >> 2) | + /* [2] */ ((r & 8u) >> 1) | + /* [3] */ ((w & 1u) << 3) | + /* [4] */ ((b & 16u) << 0) | + /* [5] */ ((x & 16u) << 1) | + /* [6] */ ((r & 16u) << 2) | + /* [7] */ ((m & 1u) << 7) + } + }; + return rex2; +} + +/* + * VEX2 encoder + */ + +static inline x86_vex2 x86_enc_vex2(uint p, uint l, uint r, uint v) +{ + x86_vex2 vex2 =3D { + .data =3D { + /* [0:1] */ ((uint)p & 3u) | + /* [2] */ ((l & 1u) << 2) | + /* [3:6] */ ((~v & 15u) << 3) | + /* [7] */ ((~r & 8u) << 4) + } + }; + return vex2; +} + +/* + * VEX3 encoder + */ + +static inline x86_vex3 x86_enc_vex3(uint m, uint p, + uint l, uint w, uint r, uint x, uint b, uint v) +{ + x86_vex3 vex3 =3D { + .data =3D { + /* [0:4] */ ((m & 31u) >> 0) | + /* [5] */ ((~b & 8u) << 2) | + /* [6] */ ((~x & 8u) << 3) | + /* [7] */ ((~r & 8u) << 4), + /* [0:1] */ ((p & 3u) >> 0) | + /* [2] */ ((l & 1u) << 2) | + /* [3:6] */ ((~v & 15u) << 3) | + /* [7] */ ((w & 1u) << 7) + } + }; + return vex3; +} + +/* + * EVEX encoder + */ + +static inline x86_evex x86_enc_evex(uint m, uint p, + uint l, uint w, uint r, uint x, uint b, uint v, + uint k, uint brd, uint z) +{ + x86_evex evex =3D { + .data =3D { + /* [0:2] */ ((m & 7u) >> 0) | + /* [3] */ ((b & 16u) >> 1) | + /* [4] */ ((~r & 16u) >> 0) | + /* [5] */ ((~b & 8u) << 2) | + /* [6] */ ((~x & 8u) << 3) | + /* [7] */ ((~r & 8u) << 4), + /* [0:1] */ ((p & 3u) >> 0) | + /* [2] */ ((~x & 16u) >> 2) | + /* [3:6] */ ((~v & 15u) << 3) | + /* [7] */ ((w & 1u) << 7), + /* [0:2] */ ((k & 7u) >> 0) | + /* [3] */ ((~v & 16u) >> 1) | + /* [4] */ ((brd & 1u) << 4) | + /* [5:6] */ ((l & 3u) << 5) | + /* [7] */ ((z & 1u) << 7) + } + }; + return evex; +} + +/* + * table sort types + */ + +enum +{ + x86_sort_none, + x86_sort_numeric, + x86_sort_alpha +}; + +/* + * table encoding prefix types + */ + +enum +{ + x86_table_none, + x86_table_lex, + x86_table_vex, + x86_table_evex +}; + +/* + * table sort indices + */ + +struct x86_table_idx +{ + size_t count; + size_t *idx; +}; + +/* + * opcode index decode tables + */ + +struct x86_acc_idx +{ + size_t map_count; + x86_opc_data *map; + size_t acc_count; + x86_acc_entry *acc; + uchar *page_offsets; +}; + +/* + * opcode index acceleration entry + */ + +struct x86_acc_entry +{ + uint idx : 24; + uint nent : 8; +}; + +/* + * opcode acceleration functions + */ + +static inline uint x86_acc_page(uint type, uint prefix, uint map) +{ + return (type & 3) | ((prefix & 15) << 2) | ((map & 7) << 6); +} + +static inline size_t x86_acc_offset(x86_acc_idx *idx, size_t acc_page) +{ + return (size_t)idx->page_offsets[acc_page] << 8; +} + +static inline x86_acc_entry *x86_acc_lookup(x86_acc_idx *idx, size_t offse= t) +{ + return idx->acc + offset; +} + +/* + * bitmap utility functions + */ + +static inline size_t x86_bitmap_idx(size_t i) { return i >> 6; } +static inline size_t x86_bitmap_shift(size_t i) { return (i & 63); } + +static inline int x86_bitmap_get(ullong *bitmap, size_t i) +{ + return (int)((bitmap[x86_bitmap_idx(i)] >> x86_bitmap_shift(i)) & 1); +} + +static inline void x86_bitmap_set(ullong *bitmap, size_t i, int value) +{ + bitmap[x86_bitmap_idx(i)] |=3D ((ullong)value << x86_bitmap_shift(i)); +} + +/* + * context for encoder, decoder, formatter and parser + */ + +struct x86_ctx +{ + uint mode; + x86_acc_idx *idx; +}; + +/* + * buffer + * + * simplified buffer with read (start) and write (end) cursors + * capacity is user managed because it does no limit checking. + */ + +struct x86_buffer +{ + uchar *data; + size_t start; + size_t end; +}; + +/* + * buffer functions + */ + +static inline void x86_buffer_init(x86_buffer *b, uchar *data) +{ + b->start =3D 0; + b->end =3D 0; + b->data =3D data; +} + +static inline void x86_buffer_init_ex(x86_buffer *b, uchar *data, + size_t start, size_t end) +{ + b->start =3D start; + b->end =3D end; + b->data =3D data; +} + +static inline size_t x86_buffer_read(x86_buffer *b, uchar *buf, size_t len) +{ + memcpy(buf, b->data + b->start, len); + b->start +=3D len; + return len; +} + +static inline size_t x86_buffer_unread(x86_buffer *b, size_t len) +{ + b->start -=3D len; + return len; +} + +static inline size_t x86_buffer_write(x86_buffer *b, uchar *buf, size_t le= n) +{ + memcpy(b->data + b->end, buf, len); + b->end +=3D len; + return len; +} + +static inline size_t x86_buffer_unwrite(x86_buffer *b, size_t len) +{ + b->end -=3D len; + return len; +} + +static inline size_t x86_out8(x86_buffer *buf, u8 v) +{ + return x86_buffer_write(buf, (void *)&v, sizeof(u8)); +} + +static inline size_t x86_out16(x86_buffer *buf, u16 v) +{ + u16 t =3D cpu_to_le16(v); + return x86_buffer_write(buf, (void *)&t, sizeof(u16)); +} + +static inline size_t x86_out32(x86_buffer *buf, u32 v) +{ + u32 t =3D cpu_to_le32(v); + return x86_buffer_write(buf, (void *)&t, sizeof(u32)); +} + +static inline size_t x86_out64(x86_buffer *buf, u64 v) +{ + u64 t =3D cpu_to_le64(v); + return x86_buffer_write(buf, (void *)&t, sizeof(u64)); +} + +static inline size_t x86_unput(x86_buffer *buf, size_t n) +{ + return x86_buffer_unwrite(buf, n); +} + +static inline u8 x86_in8(x86_buffer *buf) +{ + u8 t =3D 0; + x86_buffer_read(buf, (void *)&t, sizeof(u8)); + return t; +} + +static inline u16 x86_in16(x86_buffer *buf) +{ + u16 t =3D 0; + x86_buffer_read(buf, (void *)&t, sizeof(u16)); + return le16_to_cpu(t); +} + +static inline u32 x86_in32(x86_buffer *buf) +{ + u32 t =3D 0; + x86_buffer_read(buf, (void *)&t, sizeof(u32)); + return le32_to_cpu(t); +} + +static inline u64 x86_in64(x86_buffer *buf) +{ + u64 t =3D 0; + x86_buffer_read(buf, (void *)&t, sizeof(u64)); + return le64_to_cpu(t); +} + +/* + * metadata tables + */ + +extern const char *x86_reg_names[]; +extern const size_t x86_op_names_size; +extern const char *x86_op_names[]; +extern const size_t x86_opc_table_size; +extern const x86_opc_data x86_opc_table[]; +extern const size_t x86_opr_table_size; +extern const x86_opr_data x86_opr_table[]; +extern const size_t x86_ord_table_size; +extern const x86_ord_data x86_ord_table[]; + +/* + * encoder, decoder, table lookup, disassembly + */ + +void x86_set_debug(uint d); +size_t x86_mode_name(char *buf, size_t len, uint mode, const char *sep); +size_t x86_map_name(char *buf, size_t len, uint mode, const char *sep); +size_t x86_ord_name(char *buf, size_t len, uint ord, const char *sep); +size_t x86_ord_mnem(char *buf, size_t len, const ushort *ord); +size_t x86_opr_name(char *buf, size_t len, uint opr); +size_t x86_enc_name(char *buf, size_t len, uint enc); +const char *x86_reg_name(uint reg); +const char *x86_table_type_name(uint type); +const char *x86_table_map_name(uint map); +const char *x86_table_prefix_name(uint prefix); +int x86_enc_filter_rex(x86_rex prefix, uint enc); +int x86_enc_filter_rex2(x86_rex2 prefix, uint enc); +int x86_enc_filter_vex2(x86_vex2 prefix, uint enc); +int x86_enc_filter_vex3(x86_vex3 prefix, uint enc); +int x86_enc_filter_evex(x86_evex prefix, uint enc); +x86_table_idx x86_opc_table_identity(void); +x86_table_idx x86_opc_table_sorted(x86_table_idx tab, uint sort); +x86_table_idx x86_opc_table_filter(x86_table_idx tab, uint modes); +x86_opc_data *x86_table_lookup(x86_acc_idx *idx, const x86_opc_data *m); +void x86_print_op(const x86_opc_data *d, uint compact, uint opcode); +size_t x86_format_op(char *buf, size_t len, x86_ctx *ctx, x86_codec *c); +typedef size_t (*x86_fmt_symbol)(char *buf, size_t buflen, x86_codec *c, + size_t pc_offset); +size_t x86_format_op_symbol(char *buf, size_t buflen, x86_ctx *ctx, + x86_codec *c, size_t pc_offset, x86_fmt_symbol sym_cb); +size_t x86_format_hex(char *buf, size_t len, uchar *data, size_t datalen); +x86_ctx *x86_ctx_create(uint mode); +void x86_ctx_destroy(x86_ctx *ctx); +int x86_codec_write(x86_ctx *ctx, x86_buffer *buf, x86_codec c, size_t *le= n); +int x86_codec_read(x86_ctx *ctx, x86_buffer *buf, x86_codec *c, size_t *le= n); + +/* + * registers sand opcodes + */ + +#include "disas/x86-enums.inc" diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 3b50ecfb5409..fd8aa326948f 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -446,6 +446,7 @@ int print_insn_v850 (bfd_vma, disassemble_i= nfo*); int print_insn_tic30 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); +int print_insn_x86 (bfd_vma, disassemble_info*); int print_insn_xtensa (bfd_vma, disassemble_info*); int print_insn_riscv32 (bfd_vma, disassemble_info*); int print_insn_riscv64 (bfd_vma, disassemble_info*); diff --git a/target/i386/cpu.c b/target/i386/cpu.c index b5dd60d2812e..ff82174915cf 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -44,6 +44,7 @@ #endif =20 #include "disas/capstone.h" +#include "disas/x86.h" #include "cpu-internal.h" =20 static void x86_cpu_realizefn(DeviceState *dev, Error **errp); @@ -8507,6 +8508,12 @@ static void x86_disas_set_info(CPUState *cs, disasse= mble_info *info) : CS_MODE_16); info->cap_insn_unit =3D 1; info->cap_insn_split =3D 8; + + info->print_insn =3D print_insn_x86; + info->private_data =3D x86_ctx_create( + env->hflags & HF_CS64_MASK ? x86_modes_64 + : env->hflags & HF_CS32_MASK ? x86_modes_32 + : x86_modes_16); } =20 void x86_update_hflags(CPUX86State *env) --=20 2.43.0