VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllInstPython.py@ 107377

Last change on this file since 107377 was 107218, checked in by vboxsync, 2 months ago

ValidationKit/bootsectors: fix IEM implementation of vcmpp[sd]; bugref: 10658; jiraref:VBP-1208

  • part 3 of previous fix (r166170)
  • add microcode macros to fetch media register + memory without alignment checks:
  • add IEM_MC_FETCH_MEM_YMM_NO_AC_AND_YREG_YMM
  • add IEM_MC_FETCH_MEM_XMM_NO_AC_AND_XREG_XMM
  • add IEM_MC_FETCH_MEM_FLAT_XMM_NO_AC_AND_XREG_XMM
  • remove unused IEM_MC_FETCH_MEM_YMM_ALIGN_AVX_AND_YREG_YMM
  • remove unused IEM_MC_FETCH_MEM_XMM_ALIGN_AVX_AND_XREG_XMM

(this commit breaks the build until immediately following vdpp[sd] commit)

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 332.3 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllInstPython.py 107218 2024-12-03 09:33:07Z vboxsync $
4
5"""
6IEM instruction extractor.
7
8This script/module parses the IEMAllInstruction*.cpp.h files next to it and
9collects information about the instructions. It can then be used to generate
10disassembler tables and tests.
11"""
12
13from __future__ import print_function;
14
15__copyright__ = \
16"""
17Copyright (C) 2017-2024 Oracle and/or its affiliates.
18
19This file is part of VirtualBox base platform packages, as
20available from https://www.virtualbox.org.
21
22This program is free software; you can redistribute it and/or
23modify it under the terms of the GNU General Public License
24as published by the Free Software Foundation, in version 3 of the
25License.
26
27This program is distributed in the hope that it will be useful, but
28WITHOUT ANY WARRANTY; without even the implied warranty of
29MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30General Public License for more details.
31
32You should have received a copy of the GNU General Public License
33along with this program; if not, see <https://www.gnu.org/licenses>.
34
35The contents of this file may alternatively be used under the terms
36of the Common Development and Distribution License Version 1.0
37(CDDL), a copy of it is provided in the "COPYING.CDDL" file included
38in the VirtualBox distribution, in which case the provisions of the
39CDDL are applicable instead of those of the GPL.
40
41You may elect to license modified versions of this file under the
42terms and conditions of either the GPL or the CDDL or both.
43
44SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
45"""
46__version__ = "$Revision: 107218 $"
47
48# pylint: disable=anomalous-backslash-in-string,too-many-lines
49
50# Standard python imports.
51import os;
52import re;
53import sys;
54import traceback;
55
56## Only the main script needs to modify the path.
57#g_ksValidationKitDir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
58# 'ValidationKit');
59#sys.path.append(g_ksValidationKitDir);
60#
61#from common import utils; - Windows build boxes doesn't have pywin32.
62
63# Python 3 hacks:
64if sys.version_info[0] >= 3:
65 long = int; # pylint: disable=redefined-builtin,invalid-name
66
67
68g_kdX86EFlagsConstants = {
69 'X86_EFL_CF': 0x00000001, # RT_BIT_32(0)
70 'X86_EFL_1': 0x00000002, # RT_BIT_32(1)
71 'X86_EFL_PF': 0x00000004, # RT_BIT_32(2)
72 'X86_EFL_AF': 0x00000010, # RT_BIT_32(4)
73 'X86_EFL_ZF': 0x00000040, # RT_BIT_32(6)
74 'X86_EFL_SF': 0x00000080, # RT_BIT_32(7)
75 'X86_EFL_TF': 0x00000100, # RT_BIT_32(8)
76 'X86_EFL_IF': 0x00000200, # RT_BIT_32(9)
77 'X86_EFL_DF': 0x00000400, # RT_BIT_32(10)
78 'X86_EFL_OF': 0x00000800, # RT_BIT_32(11)
79 'X86_EFL_IOPL': 0x00003000, # (RT_BIT_32(12) | RT_BIT_32(13))
80 'X86_EFL_NT': 0x00004000, # RT_BIT_32(14)
81 'X86_EFL_RF': 0x00010000, # RT_BIT_32(16)
82 'X86_EFL_VM': 0x00020000, # RT_BIT_32(17)
83 'X86_EFL_AC': 0x00040000, # RT_BIT_32(18)
84 'X86_EFL_VIF': 0x00080000, # RT_BIT_32(19)
85 'X86_EFL_VIP': 0x00100000, # RT_BIT_32(20)
86 'X86_EFL_ID': 0x00200000, # RT_BIT_32(21)
87 'X86_EFL_LIVE_MASK': 0x003f7fd5, # UINT32_C(0x003f7fd5)
88 'X86_EFL_RA1_MASK': 0x00000002, # RT_BIT_32(1)
89};
90
91## EFlags values allowed in \@opfltest, \@opflmodify, \@opflundef, \@opflset, and \@opflclear.
92g_kdEFlagsMnemonics = {
93 # Debugger flag notation (sorted by value):
94 'cf': 'X86_EFL_CF', ##< Carry Flag.
95 'nc': '!X86_EFL_CF', ##< No Carry.
96
97 'po': 'X86_EFL_PF', ##< Parity Pdd.
98 'pe': '!X86_EFL_PF', ##< Parity Even.
99
100 'af': 'X86_EFL_AF', ##< Aux Flag.
101 'na': '!X86_EFL_AF', ##< No Aux.
102
103 'zr': 'X86_EFL_ZF', ##< ZeRo.
104 'nz': '!X86_EFL_ZF', ##< No Zero.
105
106 'ng': 'X86_EFL_SF', ##< NeGative (sign).
107 'pl': '!X86_EFL_SF', ##< PLuss (sign).
108
109 'tf': 'X86_EFL_TF', ##< Trap flag.
110
111 'ei': 'X86_EFL_IF', ##< Enabled Interrupts.
112 'di': '!X86_EFL_IF', ##< Disabled Interrupts.
113
114 'dn': 'X86_EFL_DF', ##< DowN (string op direction).
115 'up': '!X86_EFL_DF', ##< UP (string op direction).
116
117 'ov': 'X86_EFL_OF', ##< OVerflow.
118 'nv': '!X86_EFL_OF', ##< No Overflow.
119
120 'nt': 'X86_EFL_NT', ##< Nested Task.
121 'rf': 'X86_EFL_RF', ##< Resume Flag.
122 'vm': 'X86_EFL_VM', ##< Virtual-8086 Mode.
123 'ac': 'X86_EFL_AC', ##< Alignment Check.
124 'vif': 'X86_EFL_VIF', ##< Virtual Interrupt Flag.
125 'vip': 'X86_EFL_VIP', ##< Virtual Interrupt Pending.
126
127 # Reference manual notation not covered above (sorted by value):
128 'pf': 'X86_EFL_PF',
129 'zf': 'X86_EFL_ZF',
130 'sf': 'X86_EFL_SF',
131 'if': 'X86_EFL_IF',
132 'df': 'X86_EFL_DF',
133 'of': 'X86_EFL_OF',
134 'iopl': 'X86_EFL_IOPL',
135 'id': 'X86_EFL_ID',
136};
137
138## Constants and values for CR0.
139g_kdX86Cr0Constants = {
140 'X86_CR0_PE': 0x00000001, # RT_BIT_32(0)
141 'X86_CR0_MP': 0x00000002, # RT_BIT_32(1)
142 'X86_CR0_EM': 0x00000004, # RT_BIT_32(2)
143 'X86_CR0_TS': 0x00000008, # RT_BIT_32(3)
144 'X86_CR0_ET': 0x00000010, # RT_BIT_32(4)
145 'X86_CR0_NE': 0x00000020, # RT_BIT_32(5)
146 'X86_CR0_WP': 0x00010000, # RT_BIT_32(16)
147 'X86_CR0_AM': 0x00040000, # RT_BIT_32(18)
148 'X86_CR0_NW': 0x20000000, # RT_BIT_32(29)
149 'X86_CR0_CD': 0x40000000, # RT_BIT_32(30)
150 'X86_CR0_PG': 0x80000000, # RT_BIT_32(31)
151};
152
153## Constants and values for CR4.
154g_kdX86Cr4Constants = {
155 'X86_CR4_VME': 0x00000001, # RT_BIT_32(0)
156 'X86_CR4_PVI': 0x00000002, # RT_BIT_32(1)
157 'X86_CR4_TSD': 0x00000004, # RT_BIT_32(2)
158 'X86_CR4_DE': 0x00000008, # RT_BIT_32(3)
159 'X86_CR4_PSE': 0x00000010, # RT_BIT_32(4)
160 'X86_CR4_PAE': 0x00000020, # RT_BIT_32(5)
161 'X86_CR4_MCE': 0x00000040, # RT_BIT_32(6)
162 'X86_CR4_PGE': 0x00000080, # RT_BIT_32(7)
163 'X86_CR4_PCE': 0x00000100, # RT_BIT_32(8)
164 'X86_CR4_OSFXSR': 0x00000200, # RT_BIT_32(9)
165 'X86_CR4_OSXMMEEXCPT': 0x00000400, # RT_BIT_32(10)
166 'X86_CR4_VMXE': 0x00002000, # RT_BIT_32(13)
167 'X86_CR4_SMXE': 0x00004000, # RT_BIT_32(14)
168 'X86_CR4_PCIDE': 0x00020000, # RT_BIT_32(17)
169 'X86_CR4_OSXSAVE': 0x00040000, # RT_BIT_32(18)
170 'X86_CR4_SMEP': 0x00100000, # RT_BIT_32(20)
171 'X86_CR4_SMAP': 0x00200000, # RT_BIT_32(21)
172 'X86_CR4_PKE': 0x00400000, # RT_BIT_32(22)
173};
174
175## XSAVE components (XCR0).
176g_kdX86XSaveCConstants = {
177 'XSAVE_C_X87': 0x00000001,
178 'XSAVE_C_SSE': 0x00000002,
179 'XSAVE_C_YMM': 0x00000004,
180 'XSAVE_C_BNDREGS': 0x00000008,
181 'XSAVE_C_BNDCSR': 0x00000010,
182 'XSAVE_C_OPMASK': 0x00000020,
183 'XSAVE_C_ZMM_HI256': 0x00000040,
184 'XSAVE_C_ZMM_16HI': 0x00000080,
185 'XSAVE_C_PKRU': 0x00000200,
186 'XSAVE_C_LWP': 0x4000000000000000,
187 'XSAVE_C_X': 0x8000000000000000,
188 'XSAVE_C_ALL_AVX': 0x000000c4, # For clearing all AVX bits.
189 'XSAVE_C_ALL_AVX_SSE': 0x000000c6, # For clearing all AVX and SSE bits.
190};
191
192
193## \@op[1-4] locations
194g_kdOpLocations = {
195 'reg': [], ## modrm.reg
196 'rm': [], ## modrm.rm
197 'imm': [], ## immediate instruction data
198 'vvvv': [], ## VEX.vvvv
199 'imm8reg': [], ## byte immediate with register specified in bits 4 thru 7 (vpblendvb, vblendvps, vblendvpd).
200
201 # fixed registers.
202 'AL': [],
203 'rAX': [],
204 'rDX': [],
205 'CL': [],
206 'rSI': [],
207 'rDI': [],
208 'rFLAGS': [],
209 'CS': [],
210 'DS': [],
211 'ES': [],
212 'FS': [],
213 'GS': [],
214 'SS': [],
215 'XMM0': [],
216
217 # fixed valures.
218 '1': [],
219};
220
221## \@op[1-4] types
222##
223## Value fields:
224## - 0: the normal IDX_ParseXXX handler (IDX_UseModRM == IDX_ParseModRM).
225## - 1: the location (g_kdOpLocations).
226## - 2: disassembler format string version of the type.
227## - 3: disassembler OP_PARAM_XXX (XXX only).
228## - 4: IEM form matching instruction.
229##
230## Note! See the A.2.1 in SDM vol 2 for the type names.
231g_kdOpTypes = {
232 # Fixed addresses
233 'Ap': ( 'IDX_ParseImmAddrF', 'imm', '%Ap', 'Ap', 'FIXED', ),
234
235 # ModR/M.rm
236 'Eb': ( 'IDX_UseModRM', 'rm', '%Eb', 'Eb', 'RM', ),
237 'Ed': ( 'IDX_UseModRM', 'rm', '%Ed', 'Ed', 'RM', ),
238 'Ed_WO': ( 'IDX_UseModRM', 'rm', '%Ed', 'Ed', 'RM', ),
239 'Eq': ( 'IDX_UseModRM', 'rm', '%Eq', 'Eq', 'RM', ),
240 'Eq_WO': ( 'IDX_UseModRM', 'rm', '%Eq', 'Eq', 'RM', ),
241 'Ew': ( 'IDX_UseModRM', 'rm', '%Ew', 'Ew', 'RM', ),
242 'Ew_WO': ( 'IDX_UseModRM', 'rm', '%Ew', 'Ew', 'RM', ),
243 'Ev': ( 'IDX_UseModRM', 'rm', '%Ev', 'Ev', 'RM', ),
244 'Ey': ( 'IDX_UseModRM', 'rm', '%Ey', 'Ey', 'RM', ),
245 'Ey_WO': ( 'IDX_UseModRM', 'rm', '%Ey', 'Ey', 'RM', ),
246 'Qd': ( 'IDX_UseModRM', 'rm', '%Qd', 'Qd', 'RM', ),
247 'Qq': ( 'IDX_UseModRM', 'rm', '%Qq', 'Qq', 'RM', ),
248 'Qq_WO': ( 'IDX_UseModRM', 'rm', '%Qq', 'Qq', 'RM', ),
249 'Wss': ( 'IDX_UseModRM', 'rm', '%Wss', 'Wss', 'RM', ),
250 'Wss_WO': ( 'IDX_UseModRM', 'rm', '%Wss', 'Wss', 'RM', ),
251 'Wsd': ( 'IDX_UseModRM', 'rm', '%Wsd', 'Wsd', 'RM', ),
252 'Wsd_WO': ( 'IDX_UseModRM', 'rm', '%Wsd', 'Wsd', 'RM', ),
253 'Wps': ( 'IDX_UseModRM', 'rm', '%Wps', 'Wps', 'RM', ),
254 'Wps_WO': ( 'IDX_UseModRM', 'rm', '%Wps', 'Wps', 'RM', ),
255 'Wpd': ( 'IDX_UseModRM', 'rm', '%Wpd', 'Wpd', 'RM', ),
256 'Wpd_WO': ( 'IDX_UseModRM', 'rm', '%Wpd', 'Wpd', 'RM', ),
257 'Wdq': ( 'IDX_UseModRM', 'rm', '%Wdq', 'Wdq', 'RM', ),
258 'Wdq_WO': ( 'IDX_UseModRM', 'rm', '%Wdq', 'Wdq', 'RM', ),
259 'Wq': ( 'IDX_UseModRM', 'rm', '%Wq', 'Wq', 'RM', ),
260 'Wq_WO': ( 'IDX_UseModRM', 'rm', '%Wq', 'Wq', 'RM', ),
261 'WqZxReg_WO': ( 'IDX_UseModRM', 'rm', '%Wq', 'Wq', 'RM', ),
262 'Wqq': ( 'IDX_UseModRM', 'rm', '%Wqq', 'Wqq', 'RM', ),
263 'Wqq_WO': ( 'IDX_UseModRM', 'rm', '%Wqq', 'Wqq', 'RM', ),
264 'Wx': ( 'IDX_UseModRM', 'rm', '%Wx', 'Wx', 'RM', ),
265 'Wx_WO': ( 'IDX_UseModRM', 'rm', '%Wx', 'Wx', 'RM', ),
266
267 # ModR/M.rm - register only.
268 'Uq': ( 'IDX_UseModRM', 'rm', '%Uq', 'Uq', 'REG' ),
269 'UqHi': ( 'IDX_UseModRM', 'rm', '%Uq', 'UqHi', 'REG' ),
270 'Uqq': ( 'IDX_UseModRM', 'rm', '%Uqq', 'Uqq', 'REG' ),
271 'Uss': ( 'IDX_UseModRM', 'rm', '%Uss', 'Uss', 'REG' ),
272 'Uss_WO': ( 'IDX_UseModRM', 'rm', '%Uss', 'Uss', 'REG' ),
273 'Usd': ( 'IDX_UseModRM', 'rm', '%Usd', 'Usd', 'REG' ),
274 'Usd_WO': ( 'IDX_UseModRM', 'rm', '%Usd', 'Usd', 'REG' ),
275 'Ux': ( 'IDX_UseModRM', 'rm', '%Ux', 'Ux', 'REG' ),
276 'Nq': ( 'IDX_UseModRM', 'rm', '%Qq', 'Nq', 'REG' ),
277
278 # ModR/M.rm - memory only.
279 'Ma': ( 'IDX_UseModRM', 'rm', '%Ma', 'Ma', 'MEM', ), ##< Only used by BOUND.
280 'Mb_RO': ( 'IDX_UseModRM', 'rm', '%Mb', 'Mb', 'MEM', ),
281 'Md': ( 'IDX_UseModRM', 'rm', '%Md', 'Md', 'MEM', ),
282 'Md_RO': ( 'IDX_UseModRM', 'rm', '%Md', 'Md', 'MEM', ),
283 'Md_WO': ( 'IDX_UseModRM', 'rm', '%Md', 'Md', 'MEM', ),
284 'Mdq': ( 'IDX_UseModRM', 'rm', '%Mdq', 'Mdq', 'MEM', ),
285 'Mdq_WO': ( 'IDX_UseModRM', 'rm', '%Mdq', 'Mdq', 'MEM', ),
286 'Mq': ( 'IDX_UseModRM', 'rm', '%Mq', 'Mq', 'MEM', ),
287 'Mq_WO': ( 'IDX_UseModRM', 'rm', '%Mq', 'Mq', 'MEM', ),
288 'Mps_WO': ( 'IDX_UseModRM', 'rm', '%Mps', 'Mps', 'MEM', ),
289 'Mpd_WO': ( 'IDX_UseModRM', 'rm', '%Mpd', 'Mpd', 'MEM', ),
290 'Mx': ( 'IDX_UseModRM', 'rm', '%Mx', 'Mx', 'MEM', ),
291 'Mx_WO': ( 'IDX_UseModRM', 'rm', '%Mx', 'Mx', 'MEM', ),
292 'MVx': ( 'IDX_UseModRM', 'rm', '%MVx', 'MVx', 'MEM', ), ##< VSIB only. 'V' is '*' in AMD manuals.
293 'MVx_RO': ( 'IDX_UseModRM', 'rm', '%MVx', 'MVx', 'MEM', ), ##< VSIB only.
294 'MVx_WO': ( 'IDX_UseModRM', 'rm', '%MVx', 'MVx', 'MEM', ), ##< VSIB only.
295 'M_RO': ( 'IDX_UseModRM', 'rm', '%M', 'M', 'MEM', ),
296 'M_RW': ( 'IDX_UseModRM', 'rm', '%M', 'M', 'MEM', ),
297
298 # ModR/M.reg
299 'Gb': ( 'IDX_UseModRM', 'reg', '%Gb', 'Gb', '', ),
300 'Gw': ( 'IDX_UseModRM', 'reg', '%Gw', 'Gw', '', ),
301 'Gd': ( 'IDX_UseModRM', 'reg', '%Gd', 'Gd', '', ),
302 'Gv': ( 'IDX_UseModRM', 'reg', '%Gv', 'Gv', '', ),
303 'Gv_RO': ( 'IDX_UseModRM', 'reg', '%Gv', 'Gv', '', ),
304 'Gy': ( 'IDX_UseModRM', 'reg', '%Gy', 'Gy', '', ),
305 'Pd': ( 'IDX_UseModRM', 'reg', '%Pd', 'Pd', '', ),
306 'PdZx_WO': ( 'IDX_UseModRM', 'reg', '%Pd', 'PdZx', '', ),
307 'Pq': ( 'IDX_UseModRM', 'reg', '%Pq', 'Pq', '', ),
308 'Pq_WO': ( 'IDX_UseModRM', 'reg', '%Pq', 'Pq', '', ),
309 'Vd': ( 'IDX_UseModRM', 'reg', '%Vd', 'Vd', '', ),
310 'Vd_WO': ( 'IDX_UseModRM', 'reg', '%Vd', 'Vd', '', ),
311 'VdZx_WO': ( 'IDX_UseModRM', 'reg', '%Vd', 'Vd', '', ),
312 'Vdq': ( 'IDX_UseModRM', 'reg', '%Vdq', 'Vdq', '', ),
313 'Vss': ( 'IDX_UseModRM', 'reg', '%Vss', 'Vss', '', ),
314 'Vss_WO': ( 'IDX_UseModRM', 'reg', '%Vss', 'Vss', '', ),
315 'VssZx_WO': ( 'IDX_UseModRM', 'reg', '%Vss', 'Vss', '', ),
316 'Vsd': ( 'IDX_UseModRM', 'reg', '%Vsd', 'Vsd', '', ),
317 'Vsd_WO': ( 'IDX_UseModRM', 'reg', '%Vsd', 'Vsd', '', ),
318 'VsdZx_WO': ( 'IDX_UseModRM', 'reg', '%Vsd', 'Vsd', '', ),
319 'Vps': ( 'IDX_UseModRM', 'reg', '%Vps', 'Vps', '', ),
320 'Vps_WO': ( 'IDX_UseModRM', 'reg', '%Vps', 'Vps', '', ),
321 'Vpd': ( 'IDX_UseModRM', 'reg', '%Vpd', 'Vpd', '', ),
322 'Vpd_WO': ( 'IDX_UseModRM', 'reg', '%Vpd', 'Vpd', '', ),
323 'Vq': ( 'IDX_UseModRM', 'reg', '%Vq', 'Vq', '', ),
324 'Vq_WO': ( 'IDX_UseModRM', 'reg', '%Vq', 'Vq', '', ),
325 'Vdq_WO': ( 'IDX_UseModRM', 'reg', '%Vdq', 'Vdq', '', ),
326 'VqHi': ( 'IDX_UseModRM', 'reg', '%Vdq', 'VdqHi', '', ),
327 'VqHi_WO': ( 'IDX_UseModRM', 'reg', '%Vdq', 'VdqHi', '', ),
328 'VqZx_WO': ( 'IDX_UseModRM', 'reg', '%Vq', 'VqZx', '', ),
329 'Vqq': ( 'IDX_UseModRM', 'reg', '%Vqq', 'Vqq', '', ),
330 'Vqq_WO': ( 'IDX_UseModRM', 'reg', '%Vqq', 'Vqq', '', ),
331 'Vx': ( 'IDX_UseModRM', 'reg', '%Vx', 'Vx', '', ),
332 'Vx_WO': ( 'IDX_UseModRM', 'reg', '%Vx', 'Vx', '', ),
333
334 # VEX.vvvv
335 'By': ( 'IDX_UseModRM', 'vvvv', '%By', 'By', 'V', ),
336 'Hdq': ( 'IDX_UseModRM', 'vvvv', '%Hdq', 'Hdq', 'V', ),
337 'Hps': ( 'IDX_UseModRM', 'vvvv', '%Hps', 'Hps', 'V', ),
338 'Hpd': ( 'IDX_UseModRM', 'vvvv', '%Hpd', 'Hpd', 'V', ),
339 'HssHi': ( 'IDX_UseModRM', 'vvvv', '%Hx', 'HssHi', 'V', ),
340 'HsdHi': ( 'IDX_UseModRM', 'vvvv', '%Hx', 'HsdHi', 'V', ),
341 'Hq': ( 'IDX_UseModRM', 'vvvv', '%Hq', 'Hq', 'V', ),
342 'HqHi': ( 'IDX_UseModRM', 'vvvv', '%Hq', 'HqHi', 'V', ),
343 'Hqq': ( 'IDX_UseModRM', 'vvvv', '%Hqq', 'Hqq', 'V', ),
344 'Hx': ( 'IDX_UseModRM', 'vvvv', '%Hx', 'Hx', 'V', ),
345
346 # Immediate values.
347 'Ib': ( 'IDX_ParseImmByte', 'imm', '%Ib', 'Ib', '', ), ##< NB! Could be IDX_ParseImmByteSX for some instrs.
348 'Iw': ( 'IDX_ParseImmUshort', 'imm', '%Iw', 'Iw', '', ),
349 'Id': ( 'IDX_ParseImmUlong', 'imm', '%Id', 'Id', '', ),
350 'Iq': ( 'IDX_ParseImmQword', 'imm', '%Iq', 'Iq', '', ),
351 'Iv': ( 'IDX_ParseImmV', 'imm', '%Iv', 'Iv', '', ), ##< o16: word, o32: dword, o64: qword
352 'Iz': ( 'IDX_ParseImmZ', 'imm', '%Iz', 'Iz', '', ), ##< o16: word, o32|o64:dword
353
354 # Registers encoded as immediates.
355 'Lx': ( 'IDX_ParseImmByte', 'imm8reg', '%Lx', 'Lx', '', ),
356
357 # Address operands (no ModR/M).
358 'Ob': ( 'IDX_ParseImmAddr', 'imm', '%Ob', 'Ob', '', ),
359 'Ov': ( 'IDX_ParseImmAddr', 'imm', '%Ov', 'Ov', '', ),
360
361 # Relative jump targets
362 'Jb': ( 'IDX_ParseImmBRel', 'imm', '%Jb', 'Jb', '', ),
363 'Jv': ( 'IDX_ParseImmVRel', 'imm', '%Jv', 'Jv', '', ),
364
365 # DS:rSI
366 'Xb': ( 'IDX_ParseXb', 'rSI', '%eSI', 'Xb', '', ),
367 'Xv': ( 'IDX_ParseXv', 'rSI', '%eSI', 'Xv', '', ),
368 # ES:rDI
369 'Yb': ( 'IDX_ParseYb', 'rDI', '%eDI', 'Yb', '', ),
370 'Yv': ( 'IDX_ParseYv', 'rDI', '%eDI', 'Yv', '', ),
371
372 'Fv': ( 'IDX_ParseFixedReg', 'rFLAGS', '%Fv', 'Fv', '', ),
373
374 # Fixed registers.
375 'AL': ( 'IDX_ParseFixedReg', 'AL', 'al', 'REG_AL', '', ),
376 'REG_CL': ( 'IDX_ParseFixedReg', 'CL', 'cl', 'REG_CL', '', ),
377 'REG_XMM0': ( 'IDX_ParseFixedReg', 'XMM0', 'xmm0', 'REG_XMM0','', ),
378 'rAX': ( 'IDX_ParseFixedReg', 'rAX', '%eAX', 'REG_EAX', '', ),
379 'rDX': ( 'IDX_ParseFixedReg', 'rDX', '%eDX', 'REG_EDX', '', ),
380 'CS': ( 'IDX_ParseFixedReg', 'CS', 'cs', 'REG_CS', '', ), # 8086: push CS
381 'DS': ( 'IDX_ParseFixedReg', 'DS', 'ds', 'REG_DS', '', ),
382 'ES': ( 'IDX_ParseFixedReg', 'ES', 'es', 'REG_ES', '', ),
383 'FS': ( 'IDX_ParseFixedReg', 'FS', 'fs', 'REG_FS', '', ),
384 'GS': ( 'IDX_ParseFixedReg', 'GS', 'gs', 'REG_GS', '', ),
385 'SS': ( 'IDX_ParseFixedReg', 'SS', 'ss', 'REG_SS', '', ),
386
387 # Fixed values.
388 '1': ( '', '1', '1', '1', '', ),
389};
390
391# IDX_ParseFixedReg
392# IDX_ParseVexDest
393
394
395## IEMFORM_XXX mappings.
396g_kdIemForms = { # sEncoding, [ sWhere1, ... ] opcodesub ),
397 'RM': ( 'ModR/M', [ 'reg', 'rm' ], '', ),
398 'RM_REG': ( 'ModR/M', [ 'reg', 'rm' ], '11 mr/reg', ),
399 'RM_MEM': ( 'ModR/M', [ 'reg', 'rm' ], '!11 mr/reg', ),
400 'RMI': ( 'ModR/M', [ 'reg', 'rm', 'imm' ], '', ),
401 'RMI_REG': ( 'ModR/M', [ 'reg', 'rm', 'imm' ], '11 mr/reg', ),
402 'RMI_MEM': ( 'ModR/M', [ 'reg', 'rm', 'imm' ], '!11 mr/reg', ),
403 'RM0': ( 'ModR/M', [ 'reg', 'rm', 'XMM0' ], '', ),
404 'RM0_REG': ( 'ModR/M', [ 'reg', 'rm', 'XMM0' ], '11 mr/reg', ),
405 'RM0_MEM': ( 'ModR/M', [ 'reg', 'rm', 'XMM0' ], '!11 mr/reg', ),
406 'MR': ( 'ModR/M', [ 'rm', 'reg' ], '', ),
407 'MR_REG': ( 'ModR/M', [ 'rm', 'reg' ], '11 mr/reg', ),
408 'MR_MEM': ( 'ModR/M', [ 'rm', 'reg' ], '!11 mr/reg', ),
409 'MRI': ( 'ModR/M', [ 'rm', 'reg', 'imm' ], '', ),
410 'MRI_REG': ( 'ModR/M', [ 'rm', 'reg', 'imm' ], '11 mr/reg', ),
411 'MRI_MEM': ( 'ModR/M', [ 'rm', 'reg', 'imm' ], '!11 mr/reg', ),
412 'M': ( 'ModR/M', [ 'rm', ], '', ),
413 'M_REG': ( 'ModR/M', [ 'rm', ], '', ),
414 'M_MEM': ( 'ModR/M', [ 'rm', ], '', ),
415 'M1': ( 'ModR/M', [ 'rm', '1' ], '', ),
416 'M_CL': ( 'ModR/M', [ 'rm', 'CL' ], '', ), # shl/rcl/ror/++
417 'MI': ( 'ModR/M', [ 'rm', 'imm' ], '', ),
418 'MI_REG': ( 'ModR/M', [ 'rm', 'imm' ], '11 mr/reg', ),
419 'MI_MEM': ( 'ModR/M', [ 'rm', 'imm' ], '!11 mr/reg', ),
420 'R': ( 'ModR/M', [ 'reg', ], '', ),
421
422 'VEX_RM': ( 'VEX.ModR/M', [ 'reg', 'rm' ], '', ),
423 'VEX_RM_REG': ( 'VEX.ModR/M', [ 'reg', 'rm' ], '11 mr/reg', ),
424 'VEX_RM_MEM': ( 'VEX.ModR/M', [ 'reg', 'rm' ], '!11 mr/reg', ),
425 'VEX_MR': ( 'VEX.ModR/M', [ 'rm', 'reg' ], '', ),
426 'VEX_MR_REG': ( 'VEX.ModR/M', [ 'rm', 'reg' ], '11 mr/reg', ),
427 'VEX_MR_MEM': ( 'VEX.ModR/M', [ 'rm', 'reg' ], '!11 mr/reg', ),
428 'VEX_MRI': ( 'VEX.ModR/M', [ 'rm', 'reg', 'imm' ], '', ),
429 'VEX_MRI_REG': ( 'VEX.ModR/M', [ 'rm', 'reg', 'imm' ], '11 mr/reg', ),
430 'VEX_MRI_MEM': ( 'VEX.ModR/M', [ 'rm', 'reg', 'imm' ], '!11 mr/reg', ),
431 'VEX_M': ( 'VEX.ModR/M', [ 'rm', ], '' ),
432 'VEX_M_REG': ( 'VEX.ModR/M', [ 'rm', ], '' ),
433 'VEX_M_MEM': ( 'VEX.ModR/M', [ 'rm', ], '' ),
434 'VEX_R': ( 'VEX.ModR/M', [ 'reg', ], '' ),
435 'VEX_RVM': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm' ], '', ),
436 'VEX_RVM_REG': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm' ], '11 mr/reg', ),
437 'VEX_RVM_MEM': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm' ], '!11 mr/reg', ),
438 'VEX_RVMI': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm', 'imm' ], '', ),
439 'VEX_RVMI_REG': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm', 'imm' ], '11 mr/reg', ),
440 'VEX_RVMI_MEM': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm', 'imm' ], '!11 mr/reg', ),
441 'VEX_RVMR': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm', 'imm8reg' ], '', ),
442 'VEX_RVMR_REG': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm', 'imm8reg' ], '11 mr/reg', ),
443 'VEX_RVMR_MEM': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm', 'imm8reg' ], '!11 mr/reg', ),
444 'VEX_RMV': ( 'VEX.ModR/M', [ 'reg', 'rm', 'vvvv' ], '', ),
445 'VEX_RMV_REG': ( 'VEX.ModR/M', [ 'reg', 'rm', 'vvvv' ], '11 mr/reg', ),
446 'VEX_RMV_MEM': ( 'VEX.ModR/M', [ 'reg', 'rm', 'vvvv' ], '!11 mr/reg', ),
447 'VEX_RMI': ( 'VEX.ModR/M', [ 'reg', 'rm', 'imm' ], '', ),
448 'VEX_RMI_REG': ( 'VEX.ModR/M', [ 'reg', 'rm', 'imm' ], '11 mr/reg', ),
449 'VEX_RMI_MEM': ( 'VEX.ModR/M', [ 'reg', 'rm', 'imm' ], '!11 mr/reg', ),
450 'VEX_MVR': ( 'VEX.ModR/M', [ 'rm', 'vvvv', 'reg' ], '', ),
451 'VEX_MVR_REG': ( 'VEX.ModR/M', [ 'rm', 'vvvv', 'reg' ], '11 mr/reg', ),
452 'VEX_MVR_MEM': ( 'VEX.ModR/M', [ 'rm', 'vvvv', 'reg' ], '!11 mr/reg', ),
453
454 'VEX_VM': ( 'VEX.ModR/M', [ 'vvvv', 'rm' ], '', ),
455 'VEX_VM_REG': ( 'VEX.ModR/M', [ 'vvvv', 'rm' ], '11 mr/reg', ),
456 'VEX_VM_MEM': ( 'VEX.ModR/M', [ 'vvvv', 'rm' ], '!11 mr/reg', ),
457 'VEX_VMI': ( 'VEX.ModR/M', [ 'vvvv', 'rm', 'imm' ], '', ),
458 'VEX_VMI_REG': ( 'VEX.ModR/M', [ 'vvvv', 'rm', 'imm' ], '11 mr/reg', ),
459 'VEX_VMI_MEM': ( 'VEX.ModR/M', [ 'vvvv', 'rm', 'imm' ], '!11 mr/reg', ),
460
461 'FIXED': ( 'fixed', None, '', ),
462};
463
464## \@oppfx values.
465g_kdPrefixes = {
466 'none': [],
467 '0x66': [],
468 '0xf3': [],
469 '0xf2': [],
470 '!0xf3': [], # special case for bsf/tzcnt
471};
472
473## Special \@opcode tag values.
474g_kdSpecialOpcodes = {
475 '/reg': [],
476 'mr/reg': [],
477 '11 /reg': [],
478 '!11 /reg': [],
479 '11 mr/reg': [],
480 '!11 mr/reg': [],
481};
482
483## Special \@opcodesub tag values.
484## The first value is the real value for aliases.
485## The second value is for bs3cg1.
486g_kdSubOpcodes = {
487 'none': [ None, '', ],
488 '11 mr/reg': [ '11 mr/reg', '', ],
489 '11': [ '11 mr/reg', '', ], ##< alias
490 '!11 mr/reg': [ '!11 mr/reg', '', ],
491 '!11': [ '!11 mr/reg', '', ], ##< alias
492 'rex.w=0': [ 'rex.w=0', 'WZ', ],
493 'w=0': [ 'rex.w=0', '', ], ##< alias
494 'rex.w=1': [ 'rex.w=1', 'WNZ', ],
495 'w=1': [ 'rex.w=1', '', ], ##< alias
496 'vex.l=0': [ 'vex.l=0', 'L0', ],
497 'vex.l=1': [ 'vex.l=0', 'L1', ],
498 '11 mr/reg vex.l=0': [ '11 mr/reg vex.l=0', 'L0', ],
499 '11 mr/reg vex.l=1': [ '11 mr/reg vex.l=1', 'L1', ],
500 '!11 mr/reg vex.l=0': [ '!11 mr/reg vex.l=0', 'L0', ],
501 '!11 mr/reg vex.l=1': [ '!11 mr/reg vex.l=1', 'L1', ],
502 '!11 mr/reg rex.w=0': [ '!11 mr/reg rex.w=0', '', ],
503 '!11 mr/reg rex.w=1': [ '!11 mr/reg rex.w=1', '', ],
504};
505
506## Valid values for \@openc
507g_kdEncodings = {
508 'ModR/M': [ 'BS3CG1ENC_MODRM', ], ##< ModR/M
509 'VEX.ModR/M': [ 'BS3CG1ENC_VEX_MODRM', ], ##< VEX...ModR/M
510 'fixed': [ 'BS3CG1ENC_FIXED', ], ##< Fixed encoding (address, registers, unused, etc).
511 'VEX.fixed': [ 'BS3CG1ENC_VEX_FIXED', ], ##< VEX + fixed encoding (address, registers, unused, etc).
512 'prefix': [ None, ], ##< Prefix
513};
514
515## \@opunused, \@opinvalid, \@opinvlstyle
516g_kdInvalidStyles = {
517 'immediate': [], ##< CPU stops decoding immediately after the opcode.
518 'vex.modrm': [], ##< VEX+ModR/M, everyone.
519 'intel-modrm': [], ##< Intel decodes ModR/M.
520 'intel-modrm-imm8': [], ##< Intel decodes ModR/M and an 8-byte immediate.
521 'intel-opcode-modrm': [], ##< Intel decodes another opcode byte followed by ModR/M. (Unused extension tables.)
522 'intel-opcode-modrm-imm8': [], ##< Intel decodes another opcode byte followed by ModR/M and an 8-byte immediate.
523};
524
525g_kdCpuNames = {
526 '8086': (),
527 '80186': (),
528 '80286': (),
529 '80386': (),
530 '80486': (),
531};
532
533## \@opcpuid
534g_kdCpuIdFlags = {
535 'vme': 'X86_CPUID_FEATURE_EDX_VME',
536 'tsc': 'X86_CPUID_FEATURE_EDX_TSC',
537 'msr': 'X86_CPUID_FEATURE_EDX_MSR',
538 'cx8': 'X86_CPUID_FEATURE_EDX_CX8',
539 'sep': 'X86_CPUID_FEATURE_EDX_SEP',
540 'cmov': 'X86_CPUID_FEATURE_EDX_CMOV',
541 'clfsh': 'X86_CPUID_FEATURE_EDX_CLFSH',
542 'clflushopt': 'X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT',
543 'mmx': 'X86_CPUID_FEATURE_EDX_MMX',
544 'fxsr': 'X86_CPUID_FEATURE_EDX_FXSR',
545 'sse': 'X86_CPUID_FEATURE_EDX_SSE',
546 'sse2': 'X86_CPUID_FEATURE_EDX_SSE2',
547 'sse3': 'X86_CPUID_FEATURE_ECX_SSE3',
548 'pclmul': 'X86_CPUID_FEATURE_ECX_DTES64',
549 'monitor': 'X86_CPUID_FEATURE_ECX_CPLDS',
550 'vmx': 'X86_CPUID_FEATURE_ECX_VMX',
551 'smx': 'X86_CPUID_FEATURE_ECX_TM2',
552 'ssse3': 'X86_CPUID_FEATURE_ECX_SSSE3',
553 'fma': 'X86_CPUID_FEATURE_ECX_FMA',
554 'cx16': 'X86_CPUID_FEATURE_ECX_CX16',
555 'pcid': 'X86_CPUID_FEATURE_ECX_PCID',
556 'sse4.1': 'X86_CPUID_FEATURE_ECX_SSE4_1',
557 'sse4.2': 'X86_CPUID_FEATURE_ECX_SSE4_2',
558 'movbe': 'X86_CPUID_FEATURE_ECX_MOVBE',
559 'popcnt': 'X86_CPUID_FEATURE_ECX_POPCNT',
560 'aes': 'X86_CPUID_FEATURE_ECX_AES',
561 'xsave': 'X86_CPUID_FEATURE_ECX_XSAVE',
562 'avx': 'X86_CPUID_FEATURE_ECX_AVX',
563 'avx2': 'X86_CPUID_STEXT_FEATURE_EBX_AVX2',
564 'f16c': 'X86_CPUID_FEATURE_ECX_F16C',
565 'rdrand': 'X86_CPUID_FEATURE_ECX_RDRAND',
566
567 'axmmx': 'X86_CPUID_AMD_FEATURE_EDX_AXMMX',
568 '3dnowext': 'X86_CPUID_AMD_FEATURE_EDX_3DNOW_EX',
569 '3dnow': 'X86_CPUID_AMD_FEATURE_EDX_3DNOW',
570 'svm': 'X86_CPUID_AMD_FEATURE_ECX_SVM',
571 'cr8l': 'X86_CPUID_AMD_FEATURE_ECX_CR8L',
572 'abm': 'X86_CPUID_AMD_FEATURE_ECX_ABM',
573 'sse4a': 'X86_CPUID_AMD_FEATURE_ECX_SSE4A',
574 '3dnowprf': 'X86_CPUID_AMD_FEATURE_ECX_3DNOWPRF',
575 'xop': 'X86_CPUID_AMD_FEATURE_ECX_XOP',
576 'fma4': 'X86_CPUID_AMD_FEATURE_ECX_FMA4',
577};
578
579## \@ophints values.
580# pylint: disable=line-too-long
581g_kdHints = {
582 'invalid': 'DISOPTYPE_INVALID', ##<
583 'harmless': 'DISOPTYPE_HARMLESS', ##<
584 'controlflow': 'DISOPTYPE_CONTROLFLOW', ##<
585 'potentially_dangerous': 'DISOPTYPE_POTENTIALLY_DANGEROUS', ##<
586 'dangerous': 'DISOPTYPE_DANGEROUS', ##<
587 'portio': 'DISOPTYPE_PORTIO', ##<
588 'privileged': 'DISOPTYPE_PRIVILEGED', ##<
589 'privileged_notrap': 'DISOPTYPE_PRIVILEGED_NOTRAP', ##<
590 'uncond_controlflow': 'DISOPTYPE_UNCOND_CONTROLFLOW', ##<
591 'relative_controlflow': 'DISOPTYPE_RELATIVE_CONTROLFLOW', ##<
592 'cond_controlflow': 'DISOPTYPE_COND_CONTROLFLOW', ##<
593 'interrupt': 'DISOPTYPE_INTERRUPT', ##<
594 'illegal': 'DISOPTYPE_ILLEGAL', ##<
595 'rrm_dangerous': 'DISOPTYPE_RRM_DANGEROUS', ##< Some additional dangerous ones when recompiling raw r0.
596 'rrm_dangerous_16': 'DISOPTYPE_RRM_DANGEROUS_16', ##< Some additional dangerous ones when recompiling 16-bit raw r0.
597 'inhibit_irqs': 'DISOPTYPE_INHIBIT_IRQS', ##< Will or can inhibit irqs (sti, pop ss, mov ss) */
598 'x86_portio_read': 'DISOPTYPE_X86_PORTIO_READ', ##<
599 'x86_portio_write': 'DISOPTYPE_X86_PORTIO_WRITE', ##<
600 'x86_invalid_64': 'DISOPTYPE_X86_INVALID_64', ##< Invalid in 64 bits mode
601 'x86_only_64': 'DISOPTYPE_X86_ONLY_64', ##< Only valid in 64 bits mode
602 'x86_default_64_op_size': 'DISOPTYPE_X86_DEFAULT_64_OP_SIZE', ##< Default 64 bits operand size
603 'x86_forced_64_op_size': 'DISOPTYPE_X86_FORCED_64_OP_SIZE', ##< Forced 64 bits operand size; regardless of prefix bytes
604 'x86_rexb_extends_opreg': 'DISOPTYPE_X86_REXB_EXTENDS_OPREG', ##< REX.B extends the register field in the opcode byte
605 'x86_mod_fixed_11': 'DISOPTYPE_X86_MOD_FIXED_11', ##< modrm.mod is always 11b
606 'x86_forced_32_op_size_x86': 'DISOPTYPE_X86_FORCED_32_OP_SIZE_X86', ##< Forced 32 bits operand size; regardless of prefix bytes
607 ## (only in 16 & 32 bits mode!)
608 'x86_avx': 'DISOPTYPE_X86_AVX', ##< AVX,AVX2,++ instruction. Not implemented yet!
609 'x86_sse': 'DISOPTYPE_X86_SSE', ##< SSE,SSE2,SSE3,++ instruction. Not implemented yet!
610 'x86_mmx': 'DISOPTYPE_X86_MMX', ##< MMX,MMXExt,3DNow,++ instruction. Not implemented yet!
611 'x86_fpu': 'DISOPTYPE_X86_FPU', ##< FPU instruction. Not implemented yet!
612 'ignores_oz_pfx': '', ##< Ignores operand size prefix 66h.
613 'ignores_rexw': '', ##< Ignores REX.W.
614 'ignores_op_sizes': '', ##< Shorthand for "ignores_oz_pfx | ignores_op_sizes".
615 'vex_l_zero': '', ##< VEX.L must be 0.
616 'vex_l_one': '', ##< VEX.L must be 1.
617 'vex_l_ignored': '', ##< VEX.L is ignored.
618 'vex_v_zero': '', ##< VEX.V must be 0. (generate sub-table?)
619 'vex_w_zero': '', ##< REX.W/VEX.W must be 0.
620 'vex_w_one': '', ##< REX.W/VEX.W must be 1.
621 'rex_w_zero': '', ##< REX.W/VEX.W must be 0.
622 'rex_w_one': '', ##< REX.W/VEX.W must be 1.
623 'lock_allowed': '', ##< Lock prefix allowed.
624};
625# pylint: enable=line-too-long
626
627## \@opxcpttype values (see SDMv2 2.4, 2.7).
628g_kdXcptTypes = {
629 'none': [],
630 '1': [],
631 '2': [],
632 '3': [],
633 '4': [],
634 '4UA': [],
635 '5': [],
636 '5LZ': [], # LZ = VEX.L must be zero.
637 '6': [],
638 '7': [],
639 '7LZ': [],
640 '8': [],
641 '11': [],
642 '12': [],
643 'E1': [],
644 'E1NF': [],
645 'E2': [],
646 'E3': [],
647 'E3NF': [],
648 'E4': [],
649 'E4NF': [],
650 'E5': [],
651 'E5NF': [],
652 'E6': [],
653 'E6NF': [],
654 'E7NF': [],
655 'E9': [],
656 'E9NF': [],
657 'E10': [],
658 'E11': [],
659 'E12': [],
660 'E12NF': [],
661};
662
663
664def _isValidOpcodeByte(sOpcode):
665 """
666 Checks if sOpcode is a valid lower case opcode byte.
667 Returns true/false.
668 """
669 if len(sOpcode) == 4:
670 if sOpcode[:2] == '0x':
671 if sOpcode[2] in '0123456789abcdef':
672 if sOpcode[3] in '0123456789abcdef':
673 return True;
674 return False;
675
676
677class InstructionMap(object):
678 """
679 Instruction map.
680
681 The opcode map provides the lead opcode bytes (empty for the one byte
682 opcode map). An instruction can be member of multiple opcode maps as long
683 as it uses the same opcode value within the map (because of VEX).
684 """
685
686 kdEncodings = {
687 'legacy': [],
688 'vex1': [], ##< VEX or EVEX prefix with vvvvv = 1
689 'vex2': [], ##< VEX or EVEX prefix with vvvvv = 2
690 'vex3': [], ##< VEX or EVEX prefix with vvvvv = 3
691 'xop8': [], ##< XOP prefix with vvvvv = 8
692 'xop9': [], ##< XOP prefix with vvvvv = 9
693 'xop10': [], ##< XOP prefix with vvvvv = 10
694 };
695 ## Selectors.
696 ## 1. The first value is the number of table entries required by a
697 ## decoder or disassembler for this type of selector.
698 ## 2. The second value is how many entries per opcode byte if applicable.
699 kdSelectors = {
700 'byte': [ 256, 1, ], ##< next opcode byte selects the instruction (default).
701 'byte+pfx': [ 1024, 4, ], ##< next opcode byte selects the instruction together with the 0x66, 0xf2 and 0xf3 prefixes.
702 '/r': [ 8, 1, ], ##< modrm.reg selects the instruction.
703 'memreg /r':[ 16, 1, ], ##< modrm.reg and (modrm.mod == 3) selects the instruction.
704 'mod /r': [ 32, 1, ], ##< modrm.reg and modrm.mod selects the instruction.
705 '!11 /r': [ 8, 1, ], ##< modrm.reg selects the instruction with modrm.mod != 0y11.
706 '11 /r': [ 8, 1, ], ##< modrm.reg select the instruction with modrm.mod == 0y11.
707 '11': [ 64, 1, ], ##< modrm.reg and modrm.rm select the instruction with modrm.mod == 0y11.
708 };
709
710 ## Define the subentry number according to the Instruction::sPrefix
711 ## value for 'byte+pfx' selected tables.
712 kiPrefixOrder = {
713 'none': 0,
714 '0x66': 1,
715 '0xf3': 2,
716 '0xf2': 3,
717 };
718
719 def __init__(self, sName, sIemName = None, asLeadOpcodes = None, sSelector = 'byte+pfx',
720 sEncoding = 'legacy', sDisParse = None):
721 assert sSelector in self.kdSelectors;
722 assert sEncoding in self.kdEncodings;
723 if asLeadOpcodes is None:
724 asLeadOpcodes = [];
725 else:
726 for sOpcode in asLeadOpcodes:
727 assert _isValidOpcodeByte(sOpcode);
728 assert sDisParse is None or sDisParse.startswith('IDX_Parse');
729
730 self.sName = sName;
731 self.sIemName = sIemName;
732 self.asLeadOpcodes = asLeadOpcodes; ##< Lead opcode bytes formatted as hex strings like '0x0f'.
733 self.sSelector = sSelector; ##< The member selector, see kdSelectors.
734 self.sEncoding = sEncoding; ##< The encoding, see kdSelectors.
735 self.aoInstructions = [] # type: Instruction
736 self.sDisParse = sDisParse; ##< IDX_ParseXXX.
737
738 def copy(self, sNewName, sPrefixFilter = None):
739 """
740 Copies the table with filtering instruction by sPrefix if not None.
741 """
742 oCopy = InstructionMap(sNewName, sIemName = self.sIemName, asLeadOpcodes = self.asLeadOpcodes,
743 sSelector = 'byte' if sPrefixFilter is not None and self.sSelector == 'byte+pfx'
744 else self.sSelector,
745 sEncoding = self.sEncoding, sDisParse = self.sDisParse);
746 if sPrefixFilter is None:
747 oCopy.aoInstructions = list(self.aoInstructions);
748 else:
749 oCopy.aoInstructions = [oInstr for oInstr in self.aoInstructions if oInstr.sPrefix == sPrefixFilter];
750 return oCopy;
751
752 def getTableSize(self):
753 """
754 Number of table entries. This corresponds directly to the selector.
755 """
756 return self.kdSelectors[self.sSelector][0];
757
758 def getEntriesPerByte(self):
759 """
760 Number of table entries per opcode bytes.
761
762 This only really makes sense for the 'byte' and 'byte+pfx' selectors, for
763 the others it will just return 1.
764 """
765 return self.kdSelectors[self.sSelector][1];
766
767 def getInstructionIndex(self, oInstr):
768 """
769 Returns the table index for the instruction.
770 """
771 bOpcode = oInstr.getOpcodeByte();
772
773 # The byte selectors are simple. We need a full opcode byte and need just return it.
774 if self.sSelector == 'byte':
775 assert oInstr.sOpcode[:2] == '0x' and len(oInstr.sOpcode) == 4, str(oInstr);
776 return bOpcode;
777
778 # The byte + prefix selector is similarly simple, though requires a prefix as well as the full opcode.
779 if self.sSelector == 'byte+pfx':
780 assert oInstr.sOpcode[:2] == '0x' and len(oInstr.sOpcode) == 4, str(oInstr);
781 assert self.kiPrefixOrder.get(oInstr.sPrefix, -16384) >= 0;
782 return bOpcode * 4 + self.kiPrefixOrder.get(oInstr.sPrefix, -16384);
783
784 # The other selectors needs masking and shifting.
785 if self.sSelector == '/r':
786 return (bOpcode >> 3) & 0x7;
787
788 if self.sSelector == 'mod /r':
789 return (bOpcode >> 3) & 0x1f;
790
791 if self.sSelector == 'memreg /r':
792 return ((bOpcode >> 3) & 0x7) | (int((bOpcode >> 6) == 3) << 3);
793
794 if self.sSelector == '!11 /r':
795 assert (bOpcode & 0xc0) != 0xc, str(oInstr);
796 return (bOpcode >> 3) & 0x7;
797
798 if self.sSelector == '11 /r':
799 assert (bOpcode & 0xc0) == 0xc, str(oInstr);
800 return (bOpcode >> 3) & 0x7;
801
802 if self.sSelector == '11':
803 assert (bOpcode & 0xc0) == 0xc, str(oInstr);
804 return bOpcode & 0x3f;
805
806 assert False, self.sSelector;
807 return -1;
808
809 def getInstructionsInTableOrder(self):
810 """
811 Get instructions in table order.
812
813 Returns array of instructions. Normally there is exactly one
814 instruction per entry. However the entry could also be None if
815 not instruction was specified for that opcode value. Or there
816 could be a list of instructions to deal with special encodings
817 where for instance prefix (e.g. REX.W) encodes a different
818 instruction or different CPUs have different instructions or
819 prefixes in the same place.
820 """
821 # Start with empty table.
822 cTable = self.getTableSize();
823 aoTable = [None] * cTable;
824
825 # Insert the instructions.
826 for oInstr in self.aoInstructions:
827 if oInstr.sOpcode:
828 idxOpcode = self.getInstructionIndex(oInstr);
829 assert idxOpcode < cTable, str(idxOpcode);
830
831 oExisting = aoTable[idxOpcode];
832 if oExisting is None:
833 aoTable[idxOpcode] = oInstr;
834 elif not isinstance(oExisting, list):
835 aoTable[idxOpcode] = list([oExisting, oInstr]);
836 else:
837 oExisting.append(oInstr);
838
839 return aoTable;
840
841
842 def getDisasTableName(self):
843 """
844 Returns the disassembler table name for this map.
845 """
846 sName = 'g_aDisas';
847 for sWord in self.sName.split('_'):
848 if sWord == 'm': # suffix indicating modrm.mod==mem
849 sName += '_m';
850 elif sWord == 'r': # suffix indicating modrm.mod==reg
851 sName += '_r';
852 elif len(sWord) == 2 and re.match('^[a-f0-9][a-f0-9]$', sWord):
853 sName += '_' + sWord;
854 else:
855 sWord = sWord.replace('grp', 'Grp');
856 sWord = sWord.replace('map', 'Map');
857 sName += sWord[0].upper() + sWord[1:];
858 return sName;
859
860 def getDisasRangeName(self):
861 """
862 Returns the disassembler table range name for this map.
863 """
864 return self.getDisasTableName().replace('g_aDisas', 'g_Disas') + 'Range';
865
866 def isVexMap(self):
867 """ Returns True if a VEX map. """
868 return self.sEncoding.startswith('vex');
869
870
871class TestType(object):
872 """
873 Test value type.
874
875 This base class deals with integer like values. The fUnsigned constructor
876 parameter indicates the default stance on zero vs sign extending. It is
877 possible to override fUnsigned=True by prefixing the value with '+' or '-'.
878 """
879 def __init__(self, sName, acbSizes = None, fUnsigned = True):
880 self.sName = sName;
881 self.acbSizes = [1, 2, 4, 8, 16, 32] if acbSizes is None else acbSizes; # Normal sizes.
882 self.fUnsigned = fUnsigned;
883
884 class BadValue(Exception):
885 """ Bad value exception. """
886 def __init__(self, sMessage):
887 Exception.__init__(self, sMessage);
888 self.sMessage = sMessage;
889
890 ## For ascii ~ operator.
891 kdHexInv = {
892 '0': 'f',
893 '1': 'e',
894 '2': 'd',
895 '3': 'c',
896 '4': 'b',
897 '5': 'a',
898 '6': '9',
899 '7': '8',
900 '8': '7',
901 '9': '6',
902 'a': '5',
903 'b': '4',
904 'c': '3',
905 'd': '2',
906 'e': '1',
907 'f': '0',
908 };
909
910 def get(self, sValue):
911 """
912 Get the shortest normal sized byte representation of oValue.
913
914 Returns ((fSignExtend, bytearray), ) or ((fSignExtend, bytearray), (fSignExtend, bytearray), ).
915 The latter form is for AND+OR pairs where the first entry is what to
916 AND with the field and the second the one or OR with.
917
918 Raises BadValue if invalid value.
919 """
920 if not sValue:
921 raise TestType.BadValue('empty value');
922
923 # Deal with sign and detect hexadecimal or decimal.
924 fSignExtend = not self.fUnsigned;
925 if sValue[0] == '-' or sValue[0] == '+':
926 fSignExtend = True;
927 fHex = len(sValue) > 3 and sValue[1:3].lower() == '0x';
928 else:
929 fHex = len(sValue) > 2 and sValue[0:2].lower() == '0x';
930
931 # try convert it to long integer.
932 try:
933 iValue = long(sValue, 16 if fHex else 10);
934 except Exception as oXcpt:
935 raise TestType.BadValue('failed to convert "%s" to integer (%s)' % (sValue, oXcpt));
936
937 # Convert the hex string and pad it to a decent value. Negative values
938 # needs to be manually converted to something non-negative (~-n + 1).
939 if iValue >= 0:
940 sHex = hex(iValue);
941 if sys.version_info[0] < 3:
942 assert sHex[-1] == 'L';
943 sHex = sHex[:-1];
944 assert sHex[:2] == '0x';
945 sHex = sHex[2:];
946 else:
947 sHex = hex(-iValue - 1);
948 if sys.version_info[0] < 3:
949 assert sHex[-1] == 'L';
950 sHex = sHex[:-1];
951 assert sHex[:2] == '0x';
952 sHex = ''.join([self.kdHexInv[sDigit] for sDigit in sHex[2:]]);
953 if fSignExtend and sHex[0] not in [ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']:
954 sHex = 'f' + sHex;
955
956 cDigits = len(sHex);
957 if cDigits <= self.acbSizes[-1] * 2:
958 for cb in self.acbSizes:
959 cNaturalDigits = cb * 2;
960 if cDigits <= cNaturalDigits:
961 break;
962 else:
963 cNaturalDigits = self.acbSizes[-1] * 2;
964 cNaturalDigits = int((cDigits + cNaturalDigits - 1) / cNaturalDigits) * cNaturalDigits;
965 assert isinstance(cNaturalDigits, int)
966
967 if cNaturalDigits != cDigits:
968 cNeeded = cNaturalDigits - cDigits;
969 if iValue >= 0:
970 sHex = ('0' * cNeeded) + sHex;
971 else:
972 sHex = ('f' * cNeeded) + sHex;
973
974 # Invert and convert to bytearray and return it.
975 abValue = bytearray([int(sHex[offHex - 2 : offHex], 16) for offHex in range(len(sHex), 0, -2)]);
976
977 return ((fSignExtend, abValue),);
978
979 def validate(self, sValue):
980 """
981 Returns True if value is okay, error message on failure.
982 """
983 try:
984 self.get(sValue);
985 except TestType.BadValue as oXcpt:
986 return oXcpt.sMessage;
987 return True;
988
989 def isAndOrPair(self, sValue):
990 """
991 Checks if sValue is a pair.
992 """
993 _ = sValue;
994 return False;
995
996
997class TestTypeEflags(TestType):
998 """
999 Special value parsing for EFLAGS/RFLAGS/FLAGS.
1000 """
1001
1002 kdZeroValueFlags = { 'nv': 0, 'pl': 0, 'nz': 0, 'na': 0, 'pe': 0, 'nc': 0, 'di': 0, 'up': 0 };
1003
1004 def __init__(self, sName):
1005 TestType.__init__(self, sName, acbSizes = [1, 2, 4, 8], fUnsigned = True);
1006
1007 def get(self, sValue):
1008 fClear = 0;
1009 fSet = 0;
1010 for sFlag in sValue.split(','):
1011 sConstant = g_kdEFlagsMnemonics.get(sFlag, None);
1012 if sConstant is None:
1013 raise self.BadValue('Unknown flag "%s" in "%s"' % (sFlag, sValue))
1014 if sConstant[0] == '!':
1015 fClear |= g_kdX86EFlagsConstants[sConstant[1:]];
1016 else:
1017 fSet |= g_kdX86EFlagsConstants[sConstant];
1018
1019 aoSet = TestType.get(self, '0x%x' % (fSet,));
1020 if fClear != 0:
1021 aoClear = TestType.get(self, '%#x' % (fClear,))
1022 assert self.isAndOrPair(sValue) is True;
1023 return (aoClear[0], aoSet[0]);
1024 assert self.isAndOrPair(sValue) is False;
1025 return aoSet;
1026
1027 def isAndOrPair(self, sValue):
1028 for sZeroFlag in self.kdZeroValueFlags:
1029 if sValue.find(sZeroFlag) >= 0:
1030 return True;
1031 return False;
1032
1033class TestTypeFromDict(TestType):
1034 """
1035 Special value parsing for CR0.
1036 """
1037
1038 kdZeroValueFlags = { 'nv': 0, 'pl': 0, 'nz': 0, 'na': 0, 'pe': 0, 'nc': 0, 'di': 0, 'up': 0 };
1039
1040 def __init__(self, sName, kdConstantsAndValues, sConstantPrefix):
1041 TestType.__init__(self, sName, acbSizes = [1, 2, 4, 8], fUnsigned = True);
1042 self.kdConstantsAndValues = kdConstantsAndValues;
1043 self.sConstantPrefix = sConstantPrefix;
1044
1045 def get(self, sValue):
1046 fValue = 0;
1047 for sFlag in sValue.split(','):
1048 fFlagValue = self.kdConstantsAndValues.get(self.sConstantPrefix + sFlag.upper(), None);
1049 if fFlagValue is None:
1050 raise self.BadValue('Unknown flag "%s" in "%s"' % (sFlag, sValue))
1051 fValue |= fFlagValue;
1052 return TestType.get(self, '0x%x' % (fValue,));
1053
1054
1055class TestInOut(object):
1056 """
1057 One input or output state modifier.
1058
1059 This should be thought as values to modify BS3REGCTX and extended (needs
1060 to be structured) state.
1061 """
1062 ## Assigned operators.
1063 kasOperators = [
1064 '&|=', # Special AND(INV)+OR operator for use with EFLAGS.
1065 '&~=',
1066 '&=',
1067 '|=',
1068 '='
1069 ];
1070 ## Types
1071 kdTypes = {
1072 'uint': TestType('uint', fUnsigned = True),
1073 'int': TestType('int'),
1074 'efl': TestTypeEflags('efl'),
1075 'cr0': TestTypeFromDict('cr0', g_kdX86Cr0Constants, 'X86_CR0_'),
1076 'cr4': TestTypeFromDict('cr4', g_kdX86Cr4Constants, 'X86_CR4_'),
1077 'xcr0': TestTypeFromDict('xcr0', g_kdX86XSaveCConstants, 'XSAVE_C_'),
1078 };
1079 ## CPU context fields.
1080 kdFields = {
1081 # name: ( default type, [both|input|output], )
1082 # Operands.
1083 'op1': ( 'uint', 'both', ), ## \@op1
1084 'op2': ( 'uint', 'both', ), ## \@op2
1085 'op3': ( 'uint', 'both', ), ## \@op3
1086 'op4': ( 'uint', 'both', ), ## \@op4
1087 # Flags.
1088 'efl': ( 'efl', 'both', ),
1089 'efl_undef': ( 'uint', 'output', ),
1090 # 8-bit GPRs.
1091 'al': ( 'uint', 'both', ),
1092 'cl': ( 'uint', 'both', ),
1093 'dl': ( 'uint', 'both', ),
1094 'bl': ( 'uint', 'both', ),
1095 'ah': ( 'uint', 'both', ),
1096 'ch': ( 'uint', 'both', ),
1097 'dh': ( 'uint', 'both', ),
1098 'bh': ( 'uint', 'both', ),
1099 'r8l': ( 'uint', 'both', ),
1100 'r9l': ( 'uint', 'both', ),
1101 'r10l': ( 'uint', 'both', ),
1102 'r11l': ( 'uint', 'both', ),
1103 'r12l': ( 'uint', 'both', ),
1104 'r13l': ( 'uint', 'both', ),
1105 'r14l': ( 'uint', 'both', ),
1106 'r15l': ( 'uint', 'both', ),
1107 # 16-bit GPRs.
1108 'ax': ( 'uint', 'both', ),
1109 'dx': ( 'uint', 'both', ),
1110 'cx': ( 'uint', 'both', ),
1111 'bx': ( 'uint', 'both', ),
1112 'sp': ( 'uint', 'both', ),
1113 'bp': ( 'uint', 'both', ),
1114 'si': ( 'uint', 'both', ),
1115 'di': ( 'uint', 'both', ),
1116 'r8w': ( 'uint', 'both', ),
1117 'r9w': ( 'uint', 'both', ),
1118 'r10w': ( 'uint', 'both', ),
1119 'r11w': ( 'uint', 'both', ),
1120 'r12w': ( 'uint', 'both', ),
1121 'r13w': ( 'uint', 'both', ),
1122 'r14w': ( 'uint', 'both', ),
1123 'r15w': ( 'uint', 'both', ),
1124 # 32-bit GPRs.
1125 'eax': ( 'uint', 'both', ),
1126 'edx': ( 'uint', 'both', ),
1127 'ecx': ( 'uint', 'both', ),
1128 'ebx': ( 'uint', 'both', ),
1129 'esp': ( 'uint', 'both', ),
1130 'ebp': ( 'uint', 'both', ),
1131 'esi': ( 'uint', 'both', ),
1132 'edi': ( 'uint', 'both', ),
1133 'r8d': ( 'uint', 'both', ),
1134 'r9d': ( 'uint', 'both', ),
1135 'r10d': ( 'uint', 'both', ),
1136 'r11d': ( 'uint', 'both', ),
1137 'r12d': ( 'uint', 'both', ),
1138 'r13d': ( 'uint', 'both', ),
1139 'r14d': ( 'uint', 'both', ),
1140 'r15d': ( 'uint', 'both', ),
1141 # 64-bit GPRs.
1142 'rax': ( 'uint', 'both', ),
1143 'rdx': ( 'uint', 'both', ),
1144 'rcx': ( 'uint', 'both', ),
1145 'rbx': ( 'uint', 'both', ),
1146 'rsp': ( 'uint', 'both', ),
1147 'rbp': ( 'uint', 'both', ),
1148 'rsi': ( 'uint', 'both', ),
1149 'rdi': ( 'uint', 'both', ),
1150 'r8': ( 'uint', 'both', ),
1151 'r9': ( 'uint', 'both', ),
1152 'r10': ( 'uint', 'both', ),
1153 'r11': ( 'uint', 'both', ),
1154 'r12': ( 'uint', 'both', ),
1155 'r13': ( 'uint', 'both', ),
1156 'r14': ( 'uint', 'both', ),
1157 'r15': ( 'uint', 'both', ),
1158 # 16-bit, 32-bit or 64-bit registers according to operand size.
1159 'oz.rax': ( 'uint', 'both', ),
1160 'oz.rdx': ( 'uint', 'both', ),
1161 'oz.rcx': ( 'uint', 'both', ),
1162 'oz.rbx': ( 'uint', 'both', ),
1163 'oz.rsp': ( 'uint', 'both', ),
1164 'oz.rbp': ( 'uint', 'both', ),
1165 'oz.rsi': ( 'uint', 'both', ),
1166 'oz.rdi': ( 'uint', 'both', ),
1167 'oz.r8': ( 'uint', 'both', ),
1168 'oz.r9': ( 'uint', 'both', ),
1169 'oz.r10': ( 'uint', 'both', ),
1170 'oz.r11': ( 'uint', 'both', ),
1171 'oz.r12': ( 'uint', 'both', ),
1172 'oz.r13': ( 'uint', 'both', ),
1173 'oz.r14': ( 'uint', 'both', ),
1174 'oz.r15': ( 'uint', 'both', ),
1175 # Control registers.
1176 'cr0': ( 'cr0', 'both', ),
1177 'cr4': ( 'cr4', 'both', ),
1178 'xcr0': ( 'xcr0', 'both', ),
1179 # FPU Registers
1180 'fcw': ( 'uint', 'both', ),
1181 'fsw': ( 'uint', 'both', ),
1182 'ftw': ( 'uint', 'both', ),
1183 'fop': ( 'uint', 'both', ),
1184 'fpuip': ( 'uint', 'both', ),
1185 'fpucs': ( 'uint', 'both', ),
1186 'fpudp': ( 'uint', 'both', ),
1187 'fpuds': ( 'uint', 'both', ),
1188 'mxcsr': ( 'uint', 'both', ),
1189 'st0': ( 'uint', 'both', ),
1190 'st1': ( 'uint', 'both', ),
1191 'st2': ( 'uint', 'both', ),
1192 'st3': ( 'uint', 'both', ),
1193 'st4': ( 'uint', 'both', ),
1194 'st5': ( 'uint', 'both', ),
1195 'st6': ( 'uint', 'both', ),
1196 'st7': ( 'uint', 'both', ),
1197 # MMX registers.
1198 'mm0': ( 'uint', 'both', ),
1199 'mm1': ( 'uint', 'both', ),
1200 'mm2': ( 'uint', 'both', ),
1201 'mm3': ( 'uint', 'both', ),
1202 'mm4': ( 'uint', 'both', ),
1203 'mm5': ( 'uint', 'both', ),
1204 'mm6': ( 'uint', 'both', ),
1205 'mm7': ( 'uint', 'both', ),
1206 # SSE registers.
1207 'xmm0': ( 'uint', 'both', ),
1208 'xmm1': ( 'uint', 'both', ),
1209 'xmm2': ( 'uint', 'both', ),
1210 'xmm3': ( 'uint', 'both', ),
1211 'xmm4': ( 'uint', 'both', ),
1212 'xmm5': ( 'uint', 'both', ),
1213 'xmm6': ( 'uint', 'both', ),
1214 'xmm7': ( 'uint', 'both', ),
1215 'xmm8': ( 'uint', 'both', ),
1216 'xmm9': ( 'uint', 'both', ),
1217 'xmm10': ( 'uint', 'both', ),
1218 'xmm11': ( 'uint', 'both', ),
1219 'xmm12': ( 'uint', 'both', ),
1220 'xmm13': ( 'uint', 'both', ),
1221 'xmm14': ( 'uint', 'both', ),
1222 'xmm15': ( 'uint', 'both', ),
1223 'xmm0.lo': ( 'uint', 'both', ),
1224 'xmm1.lo': ( 'uint', 'both', ),
1225 'xmm2.lo': ( 'uint', 'both', ),
1226 'xmm3.lo': ( 'uint', 'both', ),
1227 'xmm4.lo': ( 'uint', 'both', ),
1228 'xmm5.lo': ( 'uint', 'both', ),
1229 'xmm6.lo': ( 'uint', 'both', ),
1230 'xmm7.lo': ( 'uint', 'both', ),
1231 'xmm8.lo': ( 'uint', 'both', ),
1232 'xmm9.lo': ( 'uint', 'both', ),
1233 'xmm10.lo': ( 'uint', 'both', ),
1234 'xmm11.lo': ( 'uint', 'both', ),
1235 'xmm12.lo': ( 'uint', 'both', ),
1236 'xmm13.lo': ( 'uint', 'both', ),
1237 'xmm14.lo': ( 'uint', 'both', ),
1238 'xmm15.lo': ( 'uint', 'both', ),
1239 'xmm0.hi': ( 'uint', 'both', ),
1240 'xmm1.hi': ( 'uint', 'both', ),
1241 'xmm2.hi': ( 'uint', 'both', ),
1242 'xmm3.hi': ( 'uint', 'both', ),
1243 'xmm4.hi': ( 'uint', 'both', ),
1244 'xmm5.hi': ( 'uint', 'both', ),
1245 'xmm6.hi': ( 'uint', 'both', ),
1246 'xmm7.hi': ( 'uint', 'both', ),
1247 'xmm8.hi': ( 'uint', 'both', ),
1248 'xmm9.hi': ( 'uint', 'both', ),
1249 'xmm10.hi': ( 'uint', 'both', ),
1250 'xmm11.hi': ( 'uint', 'both', ),
1251 'xmm12.hi': ( 'uint', 'both', ),
1252 'xmm13.hi': ( 'uint', 'both', ),
1253 'xmm14.hi': ( 'uint', 'both', ),
1254 'xmm15.hi': ( 'uint', 'both', ),
1255 'xmm0.lo.zx': ( 'uint', 'both', ),
1256 'xmm1.lo.zx': ( 'uint', 'both', ),
1257 'xmm2.lo.zx': ( 'uint', 'both', ),
1258 'xmm3.lo.zx': ( 'uint', 'both', ),
1259 'xmm4.lo.zx': ( 'uint', 'both', ),
1260 'xmm5.lo.zx': ( 'uint', 'both', ),
1261 'xmm6.lo.zx': ( 'uint', 'both', ),
1262 'xmm7.lo.zx': ( 'uint', 'both', ),
1263 'xmm8.lo.zx': ( 'uint', 'both', ),
1264 'xmm9.lo.zx': ( 'uint', 'both', ),
1265 'xmm10.lo.zx': ( 'uint', 'both', ),
1266 'xmm11.lo.zx': ( 'uint', 'both', ),
1267 'xmm12.lo.zx': ( 'uint', 'both', ),
1268 'xmm13.lo.zx': ( 'uint', 'both', ),
1269 'xmm14.lo.zx': ( 'uint', 'both', ),
1270 'xmm15.lo.zx': ( 'uint', 'both', ),
1271 'xmm0.dw0': ( 'uint', 'both', ),
1272 'xmm1.dw0': ( 'uint', 'both', ),
1273 'xmm2.dw0': ( 'uint', 'both', ),
1274 'xmm3.dw0': ( 'uint', 'both', ),
1275 'xmm4.dw0': ( 'uint', 'both', ),
1276 'xmm5.dw0': ( 'uint', 'both', ),
1277 'xmm6.dw0': ( 'uint', 'both', ),
1278 'xmm7.dw0': ( 'uint', 'both', ),
1279 'xmm8.dw0': ( 'uint', 'both', ),
1280 'xmm9.dw0': ( 'uint', 'both', ),
1281 'xmm10.dw0': ( 'uint', 'both', ),
1282 'xmm11.dw0': ( 'uint', 'both', ),
1283 'xmm12.dw0': ( 'uint', 'both', ),
1284 'xmm13.dw0': ( 'uint', 'both', ),
1285 'xmm14.dw0': ( 'uint', 'both', ),
1286 'xmm15_dw0': ( 'uint', 'both', ),
1287 # AVX registers.
1288 'ymm0': ( 'uint', 'both', ),
1289 'ymm1': ( 'uint', 'both', ),
1290 'ymm2': ( 'uint', 'both', ),
1291 'ymm3': ( 'uint', 'both', ),
1292 'ymm4': ( 'uint', 'both', ),
1293 'ymm5': ( 'uint', 'both', ),
1294 'ymm6': ( 'uint', 'both', ),
1295 'ymm7': ( 'uint', 'both', ),
1296 'ymm8': ( 'uint', 'both', ),
1297 'ymm9': ( 'uint', 'both', ),
1298 'ymm10': ( 'uint', 'both', ),
1299 'ymm11': ( 'uint', 'both', ),
1300 'ymm12': ( 'uint', 'both', ),
1301 'ymm13': ( 'uint', 'both', ),
1302 'ymm14': ( 'uint', 'both', ),
1303 'ymm15': ( 'uint', 'both', ),
1304
1305 # Special ones.
1306 'value.xcpt': ( 'uint', 'output', ),
1307 };
1308
1309 def __init__(self, sField, sOp, sValue, sType):
1310 assert sField in self.kdFields;
1311 assert sOp in self.kasOperators;
1312 self.sField = sField;
1313 self.sOp = sOp;
1314 self.sValue = sValue;
1315 self.sType = sType;
1316 assert isinstance(sField, str);
1317 assert isinstance(sOp, str);
1318 assert isinstance(sType, str);
1319 assert isinstance(sValue, str);
1320
1321
1322class TestSelector(object):
1323 """
1324 One selector for an instruction test.
1325 """
1326 ## Selector compare operators.
1327 kasCompareOps = [ '==', '!=' ];
1328 ## Selector variables and their valid values.
1329 kdVariables = {
1330 # Operand size.
1331 'size': {
1332 'o16': 'size_o16',
1333 'o32': 'size_o32',
1334 'o64': 'size_o64',
1335 },
1336 # VEX.L value.
1337 'vex.l': {
1338 '0': 'vexl_0',
1339 '1': 'vexl_1',
1340 },
1341 # Execution ring.
1342 'ring': {
1343 '0': 'ring_0',
1344 '1': 'ring_1',
1345 '2': 'ring_2',
1346 '3': 'ring_3',
1347 '0..2': 'ring_0_thru_2',
1348 '1..3': 'ring_1_thru_3',
1349 },
1350 # Basic code mode.
1351 'codebits': {
1352 '64': 'code_64bit',
1353 '32': 'code_32bit',
1354 '16': 'code_16bit',
1355 },
1356 # cpu modes.
1357 'mode': {
1358 'real': 'mode_real',
1359 'prot': 'mode_prot',
1360 'long': 'mode_long',
1361 'v86': 'mode_v86',
1362 'smm': 'mode_smm',
1363 'vmx': 'mode_vmx',
1364 'svm': 'mode_svm',
1365 },
1366 # paging on/off
1367 'paging': {
1368 'on': 'paging_on',
1369 'off': 'paging_off',
1370 },
1371 # CPU vendor
1372 'vendor': {
1373 'amd': 'vendor_amd',
1374 'intel': 'vendor_intel',
1375 'via': 'vendor_via',
1376 },
1377 };
1378 ## Selector shorthand predicates.
1379 ## These translates into variable expressions.
1380 kdPredicates = {
1381 'o16': 'size==o16',
1382 'o32': 'size==o32',
1383 'o64': 'size==o64',
1384 'ring0': 'ring==0',
1385 '!ring0': 'ring==1..3',
1386 'ring1': 'ring==1',
1387 'ring2': 'ring==2',
1388 'ring3': 'ring==3',
1389 'user': 'ring==3',
1390 'supervisor': 'ring==0..2',
1391 '16-bit': 'codebits==16',
1392 '32-bit': 'codebits==32',
1393 '64-bit': 'codebits==64',
1394 'real': 'mode==real',
1395 'prot': 'mode==prot',
1396 'long': 'mode==long',
1397 'v86': 'mode==v86',
1398 'smm': 'mode==smm',
1399 'vmx': 'mode==vmx',
1400 'svm': 'mode==svm',
1401 'paging': 'paging==on',
1402 '!paging': 'paging==off',
1403 'amd': 'vendor==amd',
1404 '!amd': 'vendor!=amd',
1405 'intel': 'vendor==intel',
1406 '!intel': 'vendor!=intel',
1407 'via': 'vendor==via',
1408 '!via': 'vendor!=via',
1409 };
1410
1411 def __init__(self, sVariable, sOp, sValue):
1412 assert sVariable in self.kdVariables;
1413 assert sOp in self.kasCompareOps;
1414 assert sValue in self.kdVariables[sVariable];
1415 self.sVariable = sVariable;
1416 self.sOp = sOp;
1417 self.sValue = sValue;
1418
1419
1420class InstructionTest(object):
1421 """
1422 Instruction test.
1423 """
1424
1425 def __init__(self, oInstr): # type: (InstructionTest, Instruction)
1426 self.oInstr = oInstr # type: InstructionTest
1427 self.aoInputs = [] # type: List[TestInOut]
1428 self.aoOutputs = [] # type: List[TestInOut]
1429 self.aoSelectors = [] # type: List[TestSelector]
1430
1431 def toString(self, fRepr = False):
1432 """
1433 Converts it to string representation.
1434 """
1435 asWords = [];
1436 if self.aoSelectors:
1437 for oSelector in self.aoSelectors:
1438 asWords.append('%s%s%s' % (oSelector.sVariable, oSelector.sOp, oSelector.sValue,));
1439 asWords.append('/');
1440
1441 for oModifier in self.aoInputs:
1442 asWords.append('%s%s%s:%s' % (oModifier.sField, oModifier.sOp, oModifier.sValue, oModifier.sType,));
1443
1444 asWords.append('->');
1445
1446 for oModifier in self.aoOutputs:
1447 asWords.append('%s%s%s:%s' % (oModifier.sField, oModifier.sOp, oModifier.sValue, oModifier.sType,));
1448
1449 if fRepr:
1450 return '<' + ' '.join(asWords) + '>';
1451 return ' '.join(asWords);
1452
1453 def __str__(self):
1454 """ Provide string represenation. """
1455 return self.toString(False);
1456
1457 def __repr__(self):
1458 """ Provide unambigious string representation. """
1459 return self.toString(True);
1460
1461class Operand(object):
1462 """
1463 Instruction operand.
1464 """
1465
1466 def __init__(self, sWhere, sType):
1467 assert sWhere in g_kdOpLocations, sWhere;
1468 assert sType in g_kdOpTypes, sType;
1469 self.sWhere = sWhere; ##< g_kdOpLocations
1470 self.sType = sType; ##< g_kdOpTypes
1471
1472 def usesModRM(self):
1473 """ Returns True if using some form of ModR/M encoding. """
1474 return self.sType[0] in ['E', 'G', 'M'];
1475
1476
1477
1478class Instruction(object): # pylint: disable=too-many-instance-attributes
1479 """
1480 Instruction.
1481 """
1482
1483 def __init__(self, sSrcFile, iLine):
1484 ## @name Core attributes.
1485 ## @{
1486 self.oParent = None # type: Instruction
1487 self.sMnemonic = None;
1488 self.sBrief = None;
1489 self.asDescSections = [] # type: List[str]
1490 self.aoMaps = [] # type: List[InstructionMap]
1491 self.aoOperands = [] # type: List[Operand]
1492 self.sPrefix = None; ##< Single prefix: None, 'none', 0x66, 0xf3, 0xf2
1493 self.sOpcode = None # type: str
1494 self.sSubOpcode = None # type: str
1495 self.sEncoding = None;
1496 self.asFlTest = None;
1497 self.asFlModify = None;
1498 self.asFlUndefined = None;
1499 self.asFlSet = None;
1500 self.asFlClear = None;
1501 self.dHints = {}; ##< Dictionary of instruction hints, flags, whatnot. (Dictionary for speed; dummy value).
1502 self.sDisEnum = None; ##< OP_XXXX value. Default is based on the uppercased mnemonic.
1503 self.asCpuIds = []; ##< The CPUID feature bit names for this instruction. If multiple, assume AND.
1504 self.asReqFeatures = []; ##< Which features are required to be enabled to run this instruction.
1505 self.aoTests = [] # type: List[InstructionTest]
1506 self.sMinCpu = None; ##< Indicates the minimum CPU required for the instruction. Not set when oCpuExpr is.
1507 self.oCpuExpr = None; ##< Some CPU restriction expression...
1508 self.sGroup = None;
1509 self.fUnused = False; ##< Unused instruction.
1510 self.fInvalid = False; ##< Invalid instruction (like UD2).
1511 self.sInvalidStyle = None; ##< Invalid behviour style (g_kdInvalidStyles),
1512 self.sXcptType = None; ##< Exception type (g_kdXcptTypes).
1513 ## @}
1514
1515 ## @name Implementation attributes.
1516 ## @{
1517 self.sStats = None;
1518 self.sFunction = None;
1519 self.fStub = False;
1520 self.fUdStub = False;
1521 ## @}
1522
1523 ## @name Decoding info
1524 ## @{
1525 self.sSrcFile = sSrcFile;
1526 self.iLineCreated = iLine;
1527 self.iLineCompleted = None;
1528 self.cOpTags = 0;
1529 self.iLineFnIemOpMacro = -1;
1530 self.iLineMnemonicMacro = -1;
1531 ## @}
1532
1533 ## @name Intermediate input fields.
1534 ## @{
1535 self.sRawDisOpNo = None;
1536 self.asRawDisParams = [];
1537 self.sRawIemOpFlags = None;
1538 self.sRawOldOpcodes = None;
1539 self.asCopyTests = [];
1540 ## @}
1541
1542 ## All the MC blocks associated with this instruction.
1543 self.aoMcBlocks = [] # type: List[McBlock]
1544
1545 def toString(self, fRepr = False):
1546 """ Turn object into a string. """
1547 aasFields = [];
1548
1549 aasFields.append(['opcode', self.sOpcode]);
1550 if self.sPrefix:
1551 aasFields.append(['prefix', self.sPrefix]);
1552 aasFields.append(['mnemonic', self.sMnemonic]);
1553 for iOperand, oOperand in enumerate(self.aoOperands):
1554 aasFields.append(['op%u' % (iOperand + 1,), '%s:%s' % (oOperand.sWhere, oOperand.sType,)]);
1555 if self.aoMaps: aasFields.append(['maps', ','.join([oMap.sName for oMap in self.aoMaps])]);
1556 aasFields.append(['encoding', self.sEncoding]);
1557 if self.dHints: aasFields.append(['hints', ','.join(self.dHints.keys())]);
1558 aasFields.append(['disenum', self.sDisEnum]);
1559 if self.asCpuIds: aasFields.append(['cpuid', ','.join(self.asCpuIds)]);
1560 aasFields.append(['group', self.sGroup]);
1561 if self.fUnused: aasFields.append(['unused', 'True']);
1562 if self.fInvalid: aasFields.append(['invalid', 'True']);
1563 aasFields.append(['invlstyle', self.sInvalidStyle]);
1564 aasFields.append(['fltest', self.asFlTest]);
1565 aasFields.append(['flmodify', self.asFlModify]);
1566 aasFields.append(['flundef', self.asFlUndefined]);
1567 aasFields.append(['flset', self.asFlSet]);
1568 aasFields.append(['flclear', self.asFlClear]);
1569 aasFields.append(['mincpu', self.sMinCpu]);
1570 aasFields.append(['stats', self.sStats]);
1571 aasFields.append(['sFunction', self.sFunction]);
1572 if self.fStub: aasFields.append(['fStub', 'True']);
1573 if self.fUdStub: aasFields.append(['fUdStub', 'True']);
1574 if self.cOpTags: aasFields.append(['optags', str(self.cOpTags)]);
1575 if self.iLineFnIemOpMacro != -1: aasFields.append(['FNIEMOP_XXX', str(self.iLineFnIemOpMacro)]);
1576 if self.iLineMnemonicMacro != -1: aasFields.append(['IEMOP_MNEMMONICn', str(self.iLineMnemonicMacro)]);
1577
1578 sRet = '<' if fRepr else '';
1579 for sField, sValue in aasFields:
1580 if sValue is not None:
1581 if len(sRet) > 1:
1582 sRet += '; ';
1583 sRet += '%s=%s' % (sField, sValue,);
1584 if fRepr:
1585 sRet += '>';
1586
1587 return sRet;
1588
1589 def __str__(self):
1590 """ Provide string represenation. """
1591 return self.toString(False);
1592
1593 def __repr__(self):
1594 """ Provide unambigious string representation. """
1595 return self.toString(True);
1596
1597 def copy(self, oMap = None, sOpcode = None, sSubOpcode = None, sPrefix = None):
1598 """
1599 Makes a copy of the object for the purpose of putting in a different map
1600 or a different place in the current map.
1601 """
1602 oCopy = Instruction(self.sSrcFile, self.iLineCreated);
1603
1604 oCopy.oParent = self;
1605 oCopy.sMnemonic = self.sMnemonic;
1606 oCopy.sBrief = self.sBrief;
1607 oCopy.asDescSections = list(self.asDescSections);
1608 oCopy.aoMaps = [oMap,] if oMap else list(self.aoMaps);
1609 oCopy.aoOperands = list(self.aoOperands); ## Deeper copy?
1610 oCopy.sPrefix = sPrefix if sPrefix else self.sPrefix;
1611 oCopy.sOpcode = sOpcode if sOpcode else self.sOpcode;
1612 oCopy.sSubOpcode = sSubOpcode if sSubOpcode else self.sSubOpcode;
1613 oCopy.sEncoding = self.sEncoding;
1614 oCopy.asFlTest = self.asFlTest;
1615 oCopy.asFlModify = self.asFlModify;
1616 oCopy.asFlUndefined = self.asFlUndefined;
1617 oCopy.asFlSet = self.asFlSet;
1618 oCopy.asFlClear = self.asFlClear;
1619 oCopy.dHints = dict(self.dHints);
1620 oCopy.sDisEnum = self.sDisEnum;
1621 oCopy.asCpuIds = list(self.asCpuIds);
1622 oCopy.asReqFeatures = list(self.asReqFeatures);
1623 oCopy.aoTests = list(self.aoTests); ## Deeper copy?
1624 oCopy.sMinCpu = self.sMinCpu;
1625 oCopy.oCpuExpr = self.oCpuExpr;
1626 oCopy.sGroup = self.sGroup;
1627 oCopy.fUnused = self.fUnused;
1628 oCopy.fInvalid = self.fInvalid;
1629 oCopy.sInvalidStyle = self.sInvalidStyle;
1630 oCopy.sXcptType = self.sXcptType;
1631
1632 oCopy.sStats = self.sStats;
1633 oCopy.sFunction = self.sFunction;
1634 oCopy.fStub = self.fStub;
1635 oCopy.fUdStub = self.fUdStub;
1636
1637 oCopy.iLineCompleted = self.iLineCompleted;
1638 oCopy.cOpTags = self.cOpTags;
1639 oCopy.iLineFnIemOpMacro = self.iLineFnIemOpMacro;
1640 oCopy.iLineMnemonicMacro = self.iLineMnemonicMacro;
1641
1642 oCopy.sRawDisOpNo = self.sRawDisOpNo;
1643 oCopy.asRawDisParams = list(self.asRawDisParams);
1644 oCopy.sRawIemOpFlags = self.sRawIemOpFlags;
1645 oCopy.sRawOldOpcodes = self.sRawOldOpcodes;
1646 oCopy.asCopyTests = list(self.asCopyTests);
1647
1648 return oCopy;
1649
1650 def getOpcodeByte(self):
1651 """
1652 Decodes sOpcode into a byte range integer value.
1653 Raises exception if sOpcode is None or invalid.
1654 """
1655 if self.sOpcode is None:
1656 raise Exception('No opcode byte for %s!' % (self,));
1657 sOpcode = str(self.sOpcode); # pylint type confusion workaround.
1658
1659 # Full hex byte form.
1660 if sOpcode[:2] == '0x':
1661 return int(sOpcode, 16);
1662
1663 # The /r form:
1664 if len(sOpcode) == 2 and sOpcode[0] == '/' and sOpcode[1].isdigit():
1665 return int(sOpcode[1:]) << 3;
1666
1667 # The 11/r form:
1668 if len(sOpcode) == 4 and sOpcode.startswith('11/') and sOpcode[-1].isdigit():
1669 return (int(sOpcode[-1:]) << 3) | 0xc0;
1670
1671 # The !11/r form (returns mod=1):
1672 ## @todo this doesn't really work...
1673 if len(sOpcode) == 5 and sOpcode.startswith('!11/') and sOpcode[-1].isdigit():
1674 return (int(sOpcode[-1:]) << 3) | 0x80;
1675
1676 raise Exception('unsupported opcode byte spec "%s" for %s' % (sOpcode, self,));
1677
1678 @staticmethod
1679 def _flagsToIntegerMask(asFlags):
1680 """
1681 Returns the integer mask value for asFlags.
1682 """
1683 uRet = 0;
1684 if asFlags:
1685 for sFlag in asFlags:
1686 sConstant = g_kdEFlagsMnemonics[sFlag];
1687 assert sConstant[0] != '!', sConstant
1688 uRet |= g_kdX86EFlagsConstants[sConstant];
1689 return uRet;
1690
1691 def getTestedFlagsMask(self):
1692 """ Returns asFlTest into a integer mask value """
1693 return self._flagsToIntegerMask(self.asFlTest);
1694
1695 def getModifiedFlagsMask(self):
1696 """ Returns asFlModify into a integer mask value """
1697 return self._flagsToIntegerMask(self.asFlModify);
1698
1699 def getUndefinedFlagsMask(self):
1700 """ Returns asFlUndefined into a integer mask value """
1701 return self._flagsToIntegerMask(self.asFlUndefined);
1702
1703 def getSetFlagsMask(self):
1704 """ Returns asFlSet into a integer mask value """
1705 return self._flagsToIntegerMask(self.asFlSet);
1706
1707 def getClearedFlagsMask(self):
1708 """ Returns asFlClear into a integer mask value """
1709 return self._flagsToIntegerMask(self.asFlClear);
1710
1711 @staticmethod
1712 def _flagsToC(asFlags):
1713 """
1714 Returns asFlags converted to X86_EFL_XXX ored together C-style.
1715 """
1716 if asFlags:
1717 asRet = [];
1718 for sFlag in asFlags:
1719 sConstant = g_kdEFlagsMnemonics[sFlag];
1720 assert sConstant[0] != '!', sConstant
1721 asRet.append(sConstant);
1722 return ' | '.join(asRet);
1723 return '0';
1724
1725 def getTestedFlagsCStyle(self):
1726 """ Returns asFlTest as C constants ored together. """
1727 return self._flagsToC(self.asFlTest);
1728
1729 def getModifiedFlagsCStyle(self):
1730 """ Returns asFlModify as C constants ored together. """
1731 return self._flagsToC(self.asFlModify);
1732
1733 def getUndefinedFlagsCStyle(self):
1734 """ Returns asFlUndefined as C constants ored together. """
1735 return self._flagsToC(self.asFlUndefined);
1736
1737 def getSetFlagsCStyle(self):
1738 """ Returns asFlSet as C constants ored together. """
1739 return self._flagsToC(self.asFlSet);
1740
1741 def getClearedFlagsCStyle(self):
1742 """ Returns asFlClear as C constants ored together. """
1743 return self._flagsToC(self.asFlClear);
1744
1745 def onlyInVexMaps(self):
1746 """ Returns True if only in VEX maps, otherwise False. (No maps -> False) """
1747 if not self.aoMaps:
1748 return False;
1749 for oMap in self.aoMaps:
1750 if not oMap.isVexMap():
1751 return False;
1752 return True;
1753
1754
1755
1756## All the instructions.
1757g_aoAllInstructions = [] # type: List[Instruction]
1758
1759## All the instructions indexed by statistics name (opstat).
1760g_dAllInstructionsByStat = {} # type: Dict[Instruction]
1761
1762## All the instructions indexed by function name (opfunction).
1763g_dAllInstructionsByFunction = {} # type: Dict[List[Instruction]]
1764
1765## Instructions tagged by oponlytest
1766g_aoOnlyTestInstructions = [] # type: List[Instruction]
1767
1768## Instruction maps.
1769g_aoInstructionMaps = [
1770 InstructionMap('one', 'g_apfnOneByteMap', sSelector = 'byte'),
1771 InstructionMap('grp1_80', asLeadOpcodes = ['0x80',], sSelector = '/r'),
1772 InstructionMap('grp1_81', asLeadOpcodes = ['0x81',], sSelector = '/r'),
1773 InstructionMap('grp1_82', asLeadOpcodes = ['0x82',], sSelector = '/r'),
1774 InstructionMap('grp1_83', asLeadOpcodes = ['0x83',], sSelector = '/r'),
1775 InstructionMap('grp1a', asLeadOpcodes = ['0x8f',], sSelector = '/r'),
1776 InstructionMap('grp2_c0', asLeadOpcodes = ['0xc0',], sSelector = '/r'),
1777 InstructionMap('grp2_c1', asLeadOpcodes = ['0xc1',], sSelector = '/r'),
1778 InstructionMap('grp2_d0', asLeadOpcodes = ['0xd0',], sSelector = '/r'),
1779 InstructionMap('grp2_d1', asLeadOpcodes = ['0xd1',], sSelector = '/r'),
1780 InstructionMap('grp2_d2', asLeadOpcodes = ['0xd2',], sSelector = '/r'),
1781 InstructionMap('grp2_d3', asLeadOpcodes = ['0xd3',], sSelector = '/r'),
1782 ## @todo g_apfnEscF1_E0toFF
1783 InstructionMap('grp3_f6', asLeadOpcodes = ['0xf6',], sSelector = '/r'),
1784 InstructionMap('grp3_f7', asLeadOpcodes = ['0xf7',], sSelector = '/r'),
1785 InstructionMap('grp4', asLeadOpcodes = ['0xfe',], sSelector = '/r'),
1786 InstructionMap('grp5', asLeadOpcodes = ['0xff',], sSelector = '/r'),
1787 InstructionMap('grp11_c6_m', asLeadOpcodes = ['0xc6',], sSelector = '!11 /r'),
1788 InstructionMap('grp11_c6_r', asLeadOpcodes = ['0xc6',], sSelector = '11'), # xabort
1789 InstructionMap('grp11_c7_m', asLeadOpcodes = ['0xc7',], sSelector = '!11 /r'),
1790 InstructionMap('grp11_c7_r', asLeadOpcodes = ['0xc7',], sSelector = '11'), # xbegin
1791
1792 InstructionMap('two0f', 'g_apfnTwoByteMap', asLeadOpcodes = ['0x0f',], sDisParse = 'IDX_ParseTwoByteEsc'),
1793 InstructionMap('grp6', 'g_apfnGroup6', asLeadOpcodes = ['0x0f', '0x00',], sSelector = '/r'),
1794 InstructionMap('grp7_m', 'g_apfnGroup7Mem', asLeadOpcodes = ['0x0f', '0x01',], sSelector = '!11 /r'),
1795 InstructionMap('grp7_r', asLeadOpcodes = ['0x0f', '0x01',], sSelector = '11'),
1796 InstructionMap('grp8', asLeadOpcodes = ['0x0f', '0xba',], sSelector = '/r'),
1797 InstructionMap('grp9', 'g_apfnGroup9RegReg', asLeadOpcodes = ['0x0f', '0xc7',], sSelector = 'mod /r'),
1798 ## @todo What about g_apfnGroup9MemReg?
1799 InstructionMap('grp10', None, asLeadOpcodes = ['0x0f', '0xb9',], sSelector = '/r'), # UD1 /w modr/m
1800 InstructionMap('grp12', 'g_apfnGroup12RegReg', asLeadOpcodes = ['0x0f', '0x71',], sSelector = 'mod /r'),
1801 InstructionMap('grp13', 'g_apfnGroup13RegReg', asLeadOpcodes = ['0x0f', '0x72',], sSelector = 'mod /r'),
1802 InstructionMap('grp14', 'g_apfnGroup14RegReg', asLeadOpcodes = ['0x0f', '0x73',], sSelector = 'mod /r'),
1803 InstructionMap('grp15', 'g_apfnGroup15MemReg', asLeadOpcodes = ['0x0f', '0xae',], sSelector = 'memreg /r'),
1804 ## @todo What about g_apfnGroup15RegReg?
1805 InstructionMap('grp16', asLeadOpcodes = ['0x0f', '0x18',], sSelector = 'mod /r'),
1806 InstructionMap('grpA17', asLeadOpcodes = ['0x0f', '0x78',], sSelector = '/r'), # AMD: EXTRQ weirdness
1807 InstructionMap('grpP', asLeadOpcodes = ['0x0f', '0x0d',], sSelector = '/r'), # AMD: prefetch
1808
1809 InstructionMap('three0f38', 'g_apfnThreeByte0f38', asLeadOpcodes = ['0x0f', '0x38',]),
1810 InstructionMap('three0f3a', 'g_apfnThreeByte0f3a', asLeadOpcodes = ['0x0f', '0x3a',]),
1811
1812 InstructionMap('vexmap1', 'g_apfnVexMap1', sEncoding = 'vex1'),
1813 InstructionMap('vexgrp12', 'g_apfnVexGroup12RegReg', sEncoding = 'vex1', asLeadOpcodes = ['0x71',], sSelector = 'mod /r'),
1814 InstructionMap('vexgrp13', 'g_apfnVexGroup13RegReg', sEncoding = 'vex1', asLeadOpcodes = ['0x72',], sSelector = 'mod /r'),
1815 InstructionMap('vexgrp14', 'g_apfnVexGroup14RegReg', sEncoding = 'vex1', asLeadOpcodes = ['0x73',], sSelector = 'mod /r'),
1816 InstructionMap('vexgrp15', 'g_apfnVexGroup15MemReg', sEncoding = 'vex1', asLeadOpcodes = ['0xae',], sSelector = 'memreg /r'),
1817 InstructionMap('vexgrp17', 'g_apfnVexGroup17_f3', sEncoding = 'vex1', asLeadOpcodes = ['0xf3',], sSelector = '/r'),
1818
1819 InstructionMap('vexmap2', 'g_apfnVexMap2', sEncoding = 'vex2'),
1820 InstructionMap('vexmap3', 'g_apfnVexMap3', sEncoding = 'vex3'),
1821
1822 InstructionMap('3dnow', asLeadOpcodes = ['0x0f', '0x0f',]),
1823 InstructionMap('xopmap8', sEncoding = 'xop8'),
1824 InstructionMap('xopmap9', sEncoding = 'xop9'),
1825 InstructionMap('xopgrp1', sEncoding = 'xop9', asLeadOpcodes = ['0x01'], sSelector = '/r'),
1826 InstructionMap('xopgrp2', sEncoding = 'xop9', asLeadOpcodes = ['0x02'], sSelector = '/r'),
1827 InstructionMap('xopgrp3', sEncoding = 'xop9', asLeadOpcodes = ['0x12'], sSelector = '/r'),
1828 InstructionMap('xopmap10', sEncoding = 'xop10'),
1829 InstructionMap('xopgrp4', sEncoding = 'xop10', asLeadOpcodes = ['0x12'], sSelector = '/r'),
1830];
1831g_dInstructionMaps = { oMap.sName: oMap for oMap in g_aoInstructionMaps };
1832g_dInstructionMapsByIemName = { oMap.sIemName: oMap for oMap in g_aoInstructionMaps };
1833
1834
1835#
1836# Decoder functions.
1837#
1838
1839class DecoderFunction(object):
1840 """
1841 Decoder function.
1842
1843 This is mainly for searching for scoping searches for variables used in
1844 microcode blocks.
1845 """
1846 def __init__(self, sSrcFile, iBeginLine, sName, asDefArgs):
1847 self.sName = sName; ##< The function name.
1848 self.asDefArgs = asDefArgs; ##< The FNIEMOP*DEF/STUB* macro argument list, 0th element is the macro name.
1849 self.sSrcFile = sSrcFile; ##< The source file the function is defined in.
1850 self.iBeginLine = iBeginLine; ##< The start line.
1851 self.iEndLine = -1; ##< The line the function (probably) ends on.
1852 self.asLines = [] # type: List[str] ##< The raw lines the function is made up of.
1853
1854 def complete(self, iEndLine, asLines):
1855 """
1856 Completes the function.
1857 """
1858 assert self.iEndLine == -1;
1859 self.iEndLine = iEndLine;
1860 self.asLines = asLines;
1861
1862
1863#
1864# "Microcode" statements and blocks
1865#
1866
1867class McStmt(object):
1868 """
1869 Statement in a microcode block.
1870 """
1871 def __init__(self, sName, asParams):
1872 self.sName = sName; ##< 'IEM_MC_XXX' or 'C++'.
1873 self.asParams = asParams;
1874 self.oUser = None;
1875
1876 def __eq__(self, oOther):
1877 if self.sName != oOther.sName:
1878 return False;
1879 if len(self.asParams) != len(oOther.asParams):
1880 return False;
1881 for iParam, sMyParam in enumerate(self.asParams):
1882 if sMyParam != oOther.asParams[iParam]:
1883 return False;
1884 return True;
1885
1886 def renderCode(self, cchIndent = 0):
1887 """
1888 Renders the code for the statement.
1889 """
1890 return ' ' * cchIndent + self.sName + '(' + ', '.join(self.asParams) + ');\n';
1891
1892 @staticmethod
1893 def renderCodeForList(aoStmts, cchIndent = 0):
1894 """
1895 Renders a list of statements.
1896 """
1897 return ''.join([oStmt.renderCode(cchIndent) for oStmt in aoStmts]);
1898
1899 @staticmethod
1900 def findStmtByNames(aoStmts, dNames):
1901 """
1902 Returns first statement with any of the given names in from the list.
1903
1904 Note! The names are passed as a dictionary for quick lookup, the value
1905 does not matter.
1906 """
1907 for oStmt in aoStmts:
1908 if oStmt.sName in dNames:
1909 return oStmt;
1910 if isinstance(oStmt, McStmtCond):
1911 oHit = McStmt.findStmtByNames(oStmt.aoIfBranch, dNames);
1912 if not oHit:
1913 oHit = McStmt.findStmtByNames(oStmt.aoElseBranch, dNames);
1914 if oHit:
1915 return oHit;
1916 return None;
1917
1918 @staticmethod
1919 def countStmtsByName(aoStmts, dNames, dRet):
1920 """
1921 Searches the given list of statements for the names in the dictionary,
1922 adding each found to dRet with an occurnece count.
1923
1924 return total number of hits;
1925 """
1926 cHits = 0;
1927 for oStmt in aoStmts:
1928 if oStmt.sName in dNames:
1929 dRet[oStmt.sName] = dRet.get(oStmt.sName, 0) + 1;
1930 cHits += 1;
1931 if isinstance(oStmt, McStmtCond):
1932 cHits += McStmt.countStmtsByName(oStmt.aoIfBranch, dNames, dRet);
1933 cHits += McStmt.countStmtsByName(oStmt.aoElseBranch, dNames, dRet);
1934 return cHits;
1935
1936 def isCppStmt(self):
1937 """ Checks if this is a C++ statement. """
1938 return self.sName.startswith('C++');
1939
1940class McStmtCond(McStmt):
1941 """
1942 Base class for conditional statements (IEM_MC_IF_XXX, IEM_MC_NATIVE_IF).
1943 """
1944 def __init__(self, sName, asParams, aoIfBranch = None, aoElseBranch = None):
1945 McStmt.__init__(self, sName, asParams);
1946 self.aoIfBranch = [] if aoIfBranch is None else list(aoIfBranch);
1947 self.aoElseBranch = [] if aoElseBranch is None else list(aoElseBranch);
1948 self.oIfBranchAnnotation = None; ##< User specific IF-branch annotation.
1949 self.oElseBranchAnnotation = None; ##< User specific IF-branch annotation.
1950 self.sNativeInfix = '' if sName != 'IEM_MC_NATIVE_IF' else '_NATIVE';
1951
1952 def renderCode(self, cchIndent = 0):
1953 sRet = ' ' * cchIndent + self.sName + '(' + ', '.join(self.asParams) + ') {\n';
1954 sRet += self.renderCodeForList(self.aoIfBranch, cchIndent + 4);
1955 if self.aoElseBranch:
1956 sRet += ' ' * cchIndent + '} IEM_MC%s_ELSE() {\n' % (self.sNativeInfix,);
1957 sRet += self.renderCodeForList(self.aoElseBranch, cchIndent + 4);
1958 sRet += ' ' * cchIndent + '} IEM_MC%s_ENDIF();\n' % (self.sNativeInfix,);
1959 return sRet;
1960
1961class McStmtNativeIf(McStmtCond):
1962 """ IEM_MC_NATIVE_IF """
1963 def __init__(self, sName, asArchitectures):
1964 McStmtCond.__init__(self, sName, ['|'.join(asArchitectures) if asArchitectures else '0',]);
1965 self.asArchitectures = asArchitectures;
1966
1967class McStmtVar(McStmt):
1968 """ IEM_MC_LOCAL, IEM_MC_LOCAL_ASSIGN, IEM_MC_LOCAL_CONST """
1969 def __init__(self, sName, asParams, sType, sVarName, sValue = None):
1970 McStmt.__init__(self, sName, asParams);
1971 self.sType = sType;
1972 self.sVarName = sVarName;
1973 self.sValue = sValue; ##< None if no assigned / const value.
1974
1975class McStmtArg(McStmtVar):
1976 """ IEM_MC_ARG, IEM_MC_ARG_CONST, IEM_MC_ARG_LOCAL_REF """
1977 def __init__(self, sName, asParams, sType, sVarName, iArg, sConstValue = None, sRef = None, sRefType = 'none'):
1978 McStmtVar.__init__(self, sName, asParams, sType, sVarName, sConstValue);
1979 self.iArg = iArg;
1980 self.sRef = sRef; ##< The reference string (local variable, register).
1981 self.sRefType = sRefType; ##< The kind of reference: 'local', 'none'.
1982 assert sRefType in ('none', 'local');
1983
1984class McStmtCall(McStmt):
1985 """ IEM_MC_CALL_* """
1986 def __init__(self, sName, asParams, iFnParam, iRcNameParam = -1):
1987 McStmt.__init__(self, sName, asParams);
1988 self.idxFn = iFnParam;
1989 self.idxParams = iFnParam + 1;
1990 self.sFn = asParams[iFnParam];
1991 self.iRcName = None if iRcNameParam < 0 else asParams[iRcNameParam];
1992
1993class McStmtAssertEFlags(McStmt):
1994 """
1995 IEM_MC_ASSERT_EFLAGS
1996 """
1997 def __init__(self, oInstruction):
1998 McStmt.__init__(self, 'IEM_MC_ASSERT_EFLAGS',
1999 [oInstruction.getTestedFlagsCStyle(), oInstruction.getModifiedFlagsCStyle(),]);
2000
2001
2002class McCppGeneric(McStmt):
2003 """
2004 Generic C++/C statement.
2005 """
2006 def __init__(self, sCode, fDecode = True, sName = 'C++', cchIndent = 0):
2007 McStmt.__init__(self, sName, [sCode,]);
2008 self.fDecode = fDecode;
2009 self.cchIndent = cchIndent;
2010
2011 def renderCode(self, cchIndent = 0):
2012 cchIndent += self.cchIndent;
2013 sRet = ' ' * cchIndent + self.asParams[0] + '\n';
2014 if self.fDecode:
2015 sRet = sRet.replace('\n', ' // C++ decode\n');
2016 else:
2017 sRet = sRet.replace('\n', ' // C++ normal\n');
2018 return sRet;
2019
2020class McCppCall(McCppGeneric):
2021 """
2022 A generic C++/C call statement.
2023
2024 The sName is still 'C++', so the function name is in the first parameter
2025 and the the arguments in the subsequent ones.
2026 """
2027 def __init__(self, sFnName, asArgs, fDecode = True, cchIndent = 0):
2028 McCppGeneric.__init__(self, sFnName, fDecode = fDecode, cchIndent = cchIndent);
2029 self.asParams.extend(asArgs);
2030
2031 def renderCode(self, cchIndent = 0):
2032 cchIndent += self.cchIndent;
2033 sRet = ' ' * cchIndent + self.asParams[0] + '(' + ', '.join(self.asParams[1:]) + ');';
2034 if self.fDecode:
2035 sRet += ' // C++ decode\n';
2036 else:
2037 sRet += ' // C++ normal\n';
2038 return sRet;
2039
2040class McCppCond(McStmtCond):
2041 """
2042 C++/C 'if' statement.
2043 """
2044 def __init__(self, sCode, fDecode = True, aoIfBranch = None, aoElseBranch = None, cchIndent = 0):
2045 McStmtCond.__init__(self, 'C++/if', [sCode,], aoIfBranch, aoElseBranch);
2046 self.fDecode = fDecode;
2047 self.cchIndent = cchIndent;
2048
2049 def renderCode(self, cchIndent = 0):
2050 cchIndent += self.cchIndent;
2051 sAnnotation = '// C++ decode' if self.fDecode else '// C++ normal';
2052 sRet = ' ' * cchIndent + 'if (' + self.asParams[0] + ') ' + sAnnotation + '\n';
2053 sRet += ' ' * cchIndent + '{\n';
2054 sRet += self.renderCodeForList(self.aoIfBranch, cchIndent + 4);
2055 sRet += ' ' * cchIndent + '}\n';
2056 if self.aoElseBranch:
2057 sRet += ' ' * cchIndent + 'else ' + sAnnotation + '\n';
2058 sRet += ' ' * cchIndent + '{\n';
2059 sRet += self.renderCodeForList(self.aoElseBranch, cchIndent + 4);
2060 sRet += ' ' * cchIndent + '}\n';
2061 return sRet;
2062
2063class McCppPreProc(McCppGeneric):
2064 """
2065 C++/C Preprocessor directive.
2066 """
2067 def __init__(self, sCode):
2068 McCppGeneric.__init__(self, sCode, False, sName = 'C++/preproc');
2069
2070 def renderCode(self, cchIndent = 0):
2071 return self.asParams[0] + '\n';
2072
2073
2074## IEM_MC_F_XXX values.
2075g_kdMcFlags = {
2076 'IEM_MC_F_ONLY_8086': (),
2077 'IEM_MC_F_MIN_186': (),
2078 'IEM_MC_F_MIN_286': (),
2079 'IEM_MC_F_NOT_286_OR_OLDER': (),
2080 'IEM_MC_F_MIN_386': ('IEM_MC_F_NOT_286_OR_OLDER',),
2081 'IEM_MC_F_MIN_486': ('IEM_MC_F_NOT_286_OR_OLDER',),
2082 'IEM_MC_F_MIN_PENTIUM': ('IEM_MC_F_NOT_286_OR_OLDER',),
2083 'IEM_MC_F_MIN_PENTIUM_II': ('IEM_MC_F_NOT_286_OR_OLDER',),
2084 'IEM_MC_F_MIN_CORE': ('IEM_MC_F_NOT_286_OR_OLDER',),
2085 'IEM_MC_F_64BIT': ('IEM_MC_F_NOT_286_OR_OLDER',),
2086 'IEM_MC_F_NOT_64BIT': (),
2087};
2088## IEM_MC_F_XXX values.
2089g_kdCImplFlags = {
2090 'IEM_CIMPL_F_BRANCH_DIRECT': (),
2091 'IEM_CIMPL_F_BRANCH_INDIRECT': (),
2092 'IEM_CIMPL_F_BRANCH_RELATIVE': (),
2093 'IEM_CIMPL_F_BRANCH_CONDITIONAL': (),
2094 'IEM_CIMPL_F_BRANCH_FAR': (),
2095 'IEM_CIMPL_F_BRANCH_ANY': ('IEM_CIMPL_F_BRANCH_DIRECT', 'IEM_CIMPL_F_BRANCH_INDIRECT',
2096 'IEM_CIMPL_F_BRANCH_RELATIVE',),
2097 'IEM_CIMPL_F_BRANCH_STACK': (),
2098 'IEM_CIMPL_F_BRANCH_STACK_FAR': (),
2099 'IEM_CIMPL_F_MODE': (),
2100 'IEM_CIMPL_F_RFLAGS': (),
2101 'IEM_CIMPL_F_INHIBIT_SHADOW': (),
2102 'IEM_CIMPL_F_STATUS_FLAGS': (),
2103 'IEM_CIMPL_F_CHECK_IRQ_AFTER': (),
2104 'IEM_CIMPL_F_CHECK_IRQ_BEFORE': (),
2105 'IEM_CIMPL_F_CHECK_IRQ_BEFORE_AND_AFTER': ('IEM_CIMPL_F_CHECK_IRQ_BEFORE', 'IEM_CIMPL_F_CHECK_IRQ_AFTER',),
2106 'IEM_CIMPL_F_VMEXIT': (),
2107 'IEM_CIMPL_F_FPU': (),
2108 'IEM_CIMPL_F_REP': (),
2109 'IEM_CIMPL_F_IO': (),
2110 'IEM_CIMPL_F_END_TB': (),
2111 'IEM_CIMPL_F_XCPT': ('IEM_CIMPL_F_BRANCH_INDIRECT', 'IEM_CIMPL_F_BRANCH_FAR',
2112 'IEM_CIMPL_F_MODE', 'IEM_CIMPL_F_RFLAGS', 'IEM_CIMPL_F_VMEXIT', ),
2113 'IEM_CIMPL_F_CALLS_CIMPL': (),
2114 'IEM_CIMPL_F_CALLS_AIMPL': (),
2115 'IEM_CIMPL_F_CALLS_AIMPL_WITH_FXSTATE': (),
2116};
2117class McBlock(object):
2118 """
2119 Microcode block (IEM_MC_BEGIN ... IEM_MC_END, IEM_MC_DEFER_TO_CIMPL_x_RET).
2120 """
2121
2122 ## @name Macro expansion types.
2123 ## @{
2124 kiMacroExp_None = 0;
2125 kiMacroExp_Entire = 1; ##< Entire block (iBeginLine == iEndLine), original line may contain multiple blocks.
2126 kiMacroExp_Partial = 2; ##< Partial/mixed (cmpxchg16b), safe to assume single block.
2127 ## @}
2128
2129 def __init__(self, sSrcFile, iBeginLine, offBeginLine, oFunction, iInFunction,
2130 oInstruction = None, cchIndent = None, fDeferToCImpl = False):
2131 ## Set if IEM_MC_DEFER_TO_CIMPL_0_RET and friends, clear if IEM_MC_BEGIN/END block.
2132 self.fDeferToCImpl = fDeferToCImpl;
2133 ## The source file containing the block.
2134 self.sSrcFile = sSrcFile;
2135 ## The line with the IEM_MC_BEGIN/IEM_MC_DEFER_TO_CIMPL_X_RET statement.
2136 self.iBeginLine = iBeginLine;
2137 ## The offset of the IEM_MC_BEGIN/IEM_MC_DEFER_TO_CIMPL_X_RET statement within the line.
2138 self.offBeginLine = offBeginLine;
2139 ## The line with the IEM_MC_END statement / last line of IEM_MC_DEFER_TO_CIMPL_X_RET.
2140 self.iEndLine = -1;
2141 ## The offset of the IEM_MC_END statement within the line / semicolon offset for defer-to.
2142 self.offEndLine = 0;
2143 ## The offset following the IEM_MC_END/IEM_MC_DEFER_TO_CIMPL_X_RET semicolon.
2144 self.offAfterEnd = 0;
2145 ## The function the block resides in.
2146 self.oFunction = oFunction;
2147 ## The name of the function the block resides in. DEPRECATED.
2148 self.sFunction = oFunction.sName;
2149 ## The block number within the function.
2150 self.iInFunction = iInFunction;
2151 ## The instruction this block is associated with - can be None.
2152 self.oInstruction = oInstruction # type: Instruction
2153 ## Indentation level of the block.
2154 self.cchIndent = cchIndent if cchIndent else offBeginLine;
2155 ## The raw lines the block is made up of.
2156 self.asLines = [] # type: List[str]
2157 ## Indicates whether the block includes macro expansion parts (kiMacroExp_None,
2158 ## kiMacroExp_Entrie, kiMacroExp_Partial).
2159 self.iMacroExp = self.kiMacroExp_None;
2160 ## IEM_MC_ARG, IEM_MC_ARG_CONST, IEM_MC_ARG_LOCAL_REF, IEM_MC_ARG_LOCAL_EFLAGS.
2161 self.aoArgs = [] # type: List[McStmtArg]
2162 ## IEM_MC_LOCAL, IEM_MC_LOCAL_CONST, IEM_MC_ARG_LOCAL_EFLAGS.
2163 self.aoLocals = [] # type: List[McStmtVar]
2164 ## IEM_MC_BEGIN: IEM_MC_F_XXX dictionary
2165 self.dsMcFlags = {} # type: Dict[str, bool]
2166 ## IEM_MC_[DEFER_TO|CALL]_CIMPL_XXX: IEM_CIMPL_F_XXX dictionary
2167 self.dsCImplFlags = {} # type: Dict[str, bool]
2168 ## Decoded statements in the block.
2169 self.aoStmts = [] # type: List[McStmt]
2170
2171 def complete(self, iEndLine, offEndLine, offAfterEnd, asLines):
2172 """
2173 Completes the microcode block.
2174 """
2175 assert self.iEndLine == -1;
2176 self.iEndLine = iEndLine;
2177 self.offEndLine = offEndLine;
2178 self.offAfterEnd = offAfterEnd;
2179 self.asLines = asLines;
2180
2181 def raiseDecodeError(self, sRawCode, off, sMessage):
2182 """ Raises a decoding error. """
2183 offStartOfLine = sRawCode.rfind('\n', 0, off) + 1;
2184 iLine = sRawCode.count('\n', 0, off);
2185 raise ParserException('%s:%d:%d: parsing error: %s'
2186 % (self.sSrcFile, self.iBeginLine + iLine, off - offStartOfLine + 1, sMessage,));
2187
2188 def raiseStmtError(self, sName, sMessage):
2189 """ Raises a statement parser error. """
2190 raise ParserException('%s:%d: %s: parsing error: %s' % (self.sSrcFile, self.iBeginLine, sName, sMessage,));
2191
2192 def checkStmtParamCount(self, sName, asParams, cParamsExpected):
2193 """ Check the parameter count, raising an error it doesn't match. """
2194 if len(asParams) != cParamsExpected:
2195 raise ParserException('%s:%d: %s: Expected %s parameters, found %s!'
2196 % (self.sSrcFile, self.iBeginLine, sName, cParamsExpected, len(asParams),));
2197 return True;
2198
2199 @staticmethod
2200 def parseMcGeneric(oSelf, sName, asParams):
2201 """ Generic parser that returns a plain McStmt object. """
2202 _ = oSelf;
2203 return McStmt(sName, asParams);
2204
2205 @staticmethod
2206 def parseMcGenericCond(oSelf, sName, asParams):
2207 """ Generic parser that returns a plain McStmtCond object. """
2208 _ = oSelf;
2209 return McStmtCond(sName, asParams);
2210
2211 kdArchVals = {
2212 'RT_ARCH_VAL_X86': True,
2213 'RT_ARCH_VAL_AMD64': True,
2214 'RT_ARCH_VAL_ARM32': True,
2215 'RT_ARCH_VAL_ARM64': True,
2216 'RT_ARCH_VAL_SPARC32': True,
2217 'RT_ARCH_VAL_SPARC64': True,
2218 };
2219
2220 @staticmethod
2221 def parseMcNativeIf(oSelf, sName, asParams):
2222 """ IEM_MC_NATIVE_IF """
2223 oSelf.checkStmtParamCount(sName, asParams, 1);
2224 if asParams[0].strip() == '0':
2225 asArchitectures = [];
2226 else:
2227 asArchitectures = [sArch.strip() for sArch in asParams[0].split('|')];
2228 for sArch in asArchitectures:
2229 if sArch not in oSelf.kdArchVals:
2230 oSelf.raiseStmtError(sName, 'Unknown architecture: %s' % (sArch,));
2231 return McStmtNativeIf(sName, asArchitectures);
2232
2233 @staticmethod
2234 def parseMcBegin(oSelf, sName, asParams):
2235 """ IEM_MC_BEGIN """
2236 oSelf.checkStmtParamCount(sName, asParams, 2);
2237 if oSelf.dsMcFlags:
2238 oSelf.raiseStmtError(sName, 'Used more than once!');
2239
2240 if asParams[0] != '0':
2241 for sFlag in asParams[0].split('|'):
2242 sFlag = sFlag.strip();
2243 if sFlag not in g_kdMcFlags:
2244 oSelf.raiseStmtError(sName, 'Unknown flag: %s' % (sFlag, ));
2245 oSelf.dsMcFlags[sFlag] = True;
2246 for sFlag2 in g_kdMcFlags[sFlag]:
2247 oSelf.dsMcFlags[sFlag2] = True;
2248
2249 if asParams[1] != '0':
2250 oSelf.parseCImplFlags(sName, asParams[1]);
2251
2252 return McBlock.parseMcGeneric(oSelf, sName, asParams);
2253
2254 @staticmethod
2255 def parseMcArg(oSelf, sName, asParams):
2256 """ IEM_MC_ARG """
2257 oSelf.checkStmtParamCount(sName, asParams, 3);
2258 oStmt = McStmtArg(sName, asParams, asParams[0], asParams[1], int(asParams[2]));
2259 oSelf.aoArgs.append(oStmt);
2260 return oStmt;
2261
2262 @staticmethod
2263 def parseMcArgConst(oSelf, sName, asParams):
2264 """ IEM_MC_ARG_CONST """
2265 oSelf.checkStmtParamCount(sName, asParams, 4);
2266 oStmt = McStmtArg(sName, asParams, asParams[0], asParams[1], int(asParams[3]), sConstValue = asParams[2]);
2267 oSelf.aoArgs.append(oStmt);
2268 return oStmt;
2269
2270 @staticmethod
2271 def parseMcArgLocalRef(oSelf, sName, asParams):
2272 """ IEM_MC_ARG_LOCAL_REF """
2273 oSelf.checkStmtParamCount(sName, asParams, 4);
2274 oStmt = McStmtArg(sName, asParams, asParams[0], asParams[1], int(asParams[3]), sRef = asParams[2], sRefType = 'local');
2275 oSelf.aoArgs.append(oStmt);
2276 return oStmt;
2277
2278 @staticmethod
2279 def parseMcArgEFlags(oSelf, sName, asParams):
2280 """ IEM_MC_ARG_EFLAGS """
2281 oSelf.checkStmtParamCount(sName, asParams, 2);
2282 # Note! We split this one up into IEM_MC_ARG and IEM_MC_FETCH_EFLAGS.
2283 oStmtArg = McStmtArg('IEM_MC_ARG', ['uint32_t', asParams[0], asParams[1]], 'uint32_t', asParams[0], int(asParams[1]));
2284 oSelf.aoArgs.append(oStmtArg);
2285 oStmtFetch = McStmt('IEM_MC_FETCH_EFLAGS', [asParams[0]]);
2286 return (oStmtArg, oStmtFetch,);
2287
2288 @staticmethod
2289 def parseMcArgLocalEFlags(oSelf, sName, asParams):
2290 """ IEM_MC_ARG_LOCAL_EFLAGS """
2291 oSelf.checkStmtParamCount(sName, asParams, 3);
2292 # Note! We split this one up into IEM_MC_LOCAL_VAR, IEM_MC_ARG_LOCAL_REF and IEM_MC_FETCH_EFLAGS.
2293 oStmtLocal = McStmtVar('IEM_MC_LOCAL', ['uint32_t', asParams[1],], 'uint32_t', asParams[1]);
2294 oSelf.aoLocals.append(oStmtLocal);
2295 oStmtArg = McStmtArg('IEM_MC_ARG_LOCAL_REF', ['uint32_t *', asParams[0], asParams[1], asParams[2]],
2296 'uint32_t *', asParams[0], int(asParams[2]), sRef = asParams[1], sRefType = 'local');
2297 oSelf.aoArgs.append(oStmtArg);
2298 oStmtFetch = McStmt('IEM_MC_FETCH_EFLAGS', [asParams[1]]);
2299 return (oStmtLocal, oStmtArg, oStmtFetch,);
2300
2301 @staticmethod
2302 def parseMcLocal(oSelf, sName, asParams):
2303 """ IEM_MC_LOCAL """
2304 oSelf.checkStmtParamCount(sName, asParams, 2);
2305 oStmt = McStmtVar(sName, asParams, asParams[0], asParams[1]);
2306 oSelf.aoLocals.append(oStmt);
2307 return oStmt;
2308
2309 @staticmethod
2310 def parseMcLocalAssign(oSelf, sName, asParams):
2311 """ IEM_MC_LOCAL_ASSIGN """
2312 oSelf.checkStmtParamCount(sName, asParams, 3);
2313 oStmt = McStmtVar(sName, asParams, asParams[0], asParams[1], sValue = asParams[2]);
2314 oSelf.aoLocals.append(oStmt);
2315 return oStmt;
2316
2317 @staticmethod
2318 def parseMcLocalConst(oSelf, sName, asParams):
2319 """ IEM_MC_LOCAL_CONST """
2320 oSelf.checkStmtParamCount(sName, asParams, 3);
2321 oStmt = McStmtVar(sName, asParams, asParams[0], asParams[1], sValue = asParams[2]);
2322 oSelf.aoLocals.append(oStmt);
2323 return oStmt;
2324
2325 @staticmethod
2326 def parseMcLocalEFlags(oSelf, sName, asParams):
2327 """ IEM_MC_LOCAL_EFLAGS"""
2328 oSelf.checkStmtParamCount(sName, asParams, 1);
2329 # Note! We split this one up into IEM_MC_LOCAL_VAR and IEM_MC_FETCH_EFLAGS just like with IEM_MC_ARG_LOCAL_EFLAGS.
2330 oStmtLocal = McStmtVar('IEM_MC_LOCAL', ['uint32_t', asParams[0]], 'uint32_t', asParams[0]);
2331 oSelf.aoLocals.append(oStmtLocal);
2332 oStmtFetch = McStmt('IEM_MC_FETCH_EFLAGS', [asParams[0]]);
2333 return (oStmtLocal, oStmtFetch,);
2334
2335 @staticmethod
2336 def parseMcCallAImpl(oSelf, sName, asParams):
2337 """ IEM_MC_CALL_AIMPL_3|4 """
2338 cArgs = int(sName[-1]);
2339 oSelf.checkStmtParamCount(sName, asParams, 3 + cArgs);
2340 oSelf.aoLocals.append(McStmtVar('IEM_MC_LOCAL', [asParams[0], asParams[1]], asParams[0], asParams[1]));
2341 return McStmtCall(sName, asParams, 2, 1);
2342
2343 @staticmethod
2344 def parseMcCallVoidAImpl(oSelf, sName, asParams):
2345 """ IEM_MC_CALL_VOID_AIMPL_2|3 """
2346 cArgs = int(sName[-1]);
2347 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2348 return McStmtCall(sName, asParams, 0);
2349
2350 @staticmethod
2351 def parseMcCallAvxAImpl(oSelf, sName, asParams):
2352 """ IEM_MC_CALL_AVX_AIMPL_2|3 """
2353 cArgs = int(sName[-1]);
2354 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2355 return McStmtCall(sName, asParams, 0);
2356
2357 @staticmethod
2358 def parseMcCallFpuAImpl(oSelf, sName, asParams):
2359 """ IEM_MC_CALL_FPU_AIMPL_1|2|3 """
2360 cArgs = int(sName[-1]);
2361 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2362 return McStmtCall(sName, asParams, 0);
2363
2364 @staticmethod
2365 def parseMcCallMmxAImpl(oSelf, sName, asParams):
2366 """ IEM_MC_CALL_MMX_AIMPL_2|3 """
2367 cArgs = int(sName[-1]);
2368 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2369 return McStmtCall(sName, asParams, 0);
2370
2371 @staticmethod
2372 def parseMcCallSseAImpl(oSelf, sName, asParams):
2373 """ IEM_MC_CALL_SSE_AIMPL_2|3 """
2374 cArgs = int(sName[-1]);
2375 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2376 return McStmtCall(sName, asParams, 0);
2377
2378 def parseCImplFlags(self, sName, sFlags):
2379 """
2380 Helper for parseMcCallCImpl and parseMcDeferToCImpl to validate and
2381 merge a bunch of IEM_CIMPL_F_XXX value into dsCImplFlags.
2382 """
2383 if sFlags != '0':
2384 sFlags = self.stripComments(sFlags);
2385 #print('debug: %s: %s' % (self.oFunction.sName,' | '.join(''.join(sFlags.split()).split('|')),));
2386 for sFlag in sFlags.split('|'):
2387 sFlag = sFlag.strip();
2388 if sFlag[0] == '(': sFlag = sFlag[1:].strip();
2389 if sFlag[-1] == ')': sFlag = sFlag[:-1].strip();
2390 #print('debug: %s' % sFlag)
2391 if sFlag not in g_kdCImplFlags:
2392 if sFlag == '0':
2393 continue;
2394 self.raiseStmtError(sName, 'Unknown flag: %s' % (sFlag, ));
2395 self.dsCImplFlags[sFlag] = True;
2396 for sFlag2 in g_kdCImplFlags[sFlag]:
2397 self.dsCImplFlags[sFlag2] = True;
2398 return None;
2399
2400 @staticmethod
2401 def parseMcCallCImpl(oSelf, sName, asParams):
2402 """ IEM_MC_CALL_CIMPL_0|1|2|3|4|5 """
2403 cArgs = int(sName[-1]);
2404 oSelf.checkStmtParamCount(sName, asParams, 3 + cArgs);
2405 oSelf.parseCImplFlags(sName, asParams[0]);
2406 return McStmtCall(sName, asParams, 2);
2407
2408 @staticmethod
2409 def parseMcDeferToCImpl(oSelf, sName, asParams):
2410 """ IEM_MC_DEFER_TO_CIMPL_[0|1|2|3]_RET """
2411 # Note! This code is called by workerIemMcDeferToCImplXRet.
2412 #print('debug: %s, %s,...' % (sName, asParams[0],));
2413 cArgs = int(sName[-5]);
2414 oSelf.checkStmtParamCount(sName, asParams, 3 + cArgs);
2415 oSelf.parseCImplFlags(sName, asParams[0]);
2416 return McStmtCall(sName, asParams, 2);
2417
2418 @staticmethod
2419 def stripComments(sCode):
2420 """ Returns sCode with comments removed. """
2421 off = 0;
2422 while off < len(sCode):
2423 off = sCode.find('/', off);
2424 if off < 0 or off + 1 >= len(sCode):
2425 break;
2426
2427 if sCode[off + 1] == '/':
2428 # C++ comment.
2429 offEnd = sCode.find('\n', off + 2);
2430 if offEnd < 0:
2431 return sCode[:off].rstrip();
2432 sCode = sCode[ : off] + sCode[offEnd : ];
2433 off += 1;
2434
2435 elif sCode[off + 1] == '*':
2436 # C comment
2437 offEnd = sCode.find('*/', off + 2);
2438 if offEnd < 0:
2439 return sCode[:off].rstrip();
2440 sSep = ' ';
2441 if (off > 0 and sCode[off - 1].isspace()) or (offEnd + 2 < len(sCode) and sCode[offEnd + 2].isspace()):
2442 sSep = '';
2443 sCode = sCode[ : off] + sSep + sCode[offEnd + 2 : ];
2444 off += len(sSep);
2445
2446 else:
2447 # Not a comment.
2448 off += 1;
2449 return sCode;
2450
2451 @staticmethod
2452 def extractParam(sCode, offParam):
2453 """
2454 Extracts the parameter value at offParam in sCode.
2455 Returns stripped value and the end offset of the terminating ',' or ')'.
2456 """
2457 # Extract it.
2458 cNesting = 0;
2459 offStart = offParam;
2460 while offParam < len(sCode):
2461 ch = sCode[offParam];
2462 if ch == '(':
2463 cNesting += 1;
2464 elif ch == ')':
2465 if cNesting == 0:
2466 break;
2467 cNesting -= 1;
2468 elif ch == ',' and cNesting == 0:
2469 break;
2470 offParam += 1;
2471 return (sCode[offStart : offParam].strip(), offParam);
2472
2473 @staticmethod
2474 def extractParams(sCode, offOpenParen):
2475 """
2476 Parses a parameter list.
2477 Returns the list of parameter values and the offset of the closing parentheses.
2478 Returns (None, len(sCode)) on if no closing parentheses was found.
2479 """
2480 assert sCode[offOpenParen] == '(';
2481 asParams = [];
2482 off = offOpenParen + 1;
2483 while off < len(sCode):
2484 ch = sCode[off];
2485 if ch.isspace():
2486 off += 1;
2487 elif ch != ')':
2488 (sParam, off) = McBlock.extractParam(sCode, off);
2489 asParams.append(sParam);
2490 assert off < len(sCode), 'off=%s sCode=%s:"%s"' % (off, len(sCode), sCode,);
2491 if sCode[off] == ',':
2492 off += 1;
2493 else:
2494 return (asParams, off);
2495 return (None, off);
2496
2497 @staticmethod
2498 def findClosingBraces(sCode, off, offStop):
2499 """
2500 Finds the matching '}' for the '{' at off in sCode.
2501 Returns offset of the matching '}' on success, otherwise -1.
2502
2503 Note! Does not take comments into account.
2504 """
2505 cDepth = 1;
2506 off += 1;
2507 while off < offStop:
2508 offClose = sCode.find('}', off, offStop);
2509 if offClose < 0:
2510 break;
2511 cDepth += sCode.count('{', off, offClose);
2512 cDepth -= 1;
2513 if cDepth == 0:
2514 return offClose;
2515 off = offClose + 1;
2516 return -1;
2517
2518 @staticmethod
2519 def countSpacesAt(sCode, off, offStop):
2520 """ Returns the number of space characters at off in sCode. """
2521 offStart = off;
2522 while off < offStop and sCode[off].isspace():
2523 off += 1;
2524 return off - offStart;
2525
2526 @staticmethod
2527 def skipSpacesAt(sCode, off, offStop):
2528 """ Returns first offset at or after off for a non-space character. """
2529 return off + McBlock.countSpacesAt(sCode, off, offStop);
2530
2531 @staticmethod
2532 def isSubstrAt(sStr, off, sSubStr):
2533 """ Returns true of sSubStr is found at off in sStr. """
2534 return sStr[off : off + len(sSubStr)] == sSubStr;
2535
2536 koReCppCtrlStmts = re.compile(r'\b(if\s*[(]|else\b|while\s*[(]|for\s*[(]|do\b)');
2537 koReIemDecoderVars = re.compile( r'iem\.s\.(fPrefixes|uRexReg|uRexB|uRexIndex|iEffSeg|offModRm|cbOpcode|offOpcode'
2538 + r'|enmEffOpSize|enmDefOpSize|enmDefAddrMode|enmEffAddrMode|idxPrefix'
2539 + r'|uVex3rdReg|uVexLength|fEvxStuff|uFpuOpcode|abOpcode'
2540 + r')');
2541
2542 kaasConditions = (
2543 ( 'IEM_MC_IF_', 'IEM_MC_ELSE', 'IEM_MC_ENDIF' ),
2544 ( 'IEM_MC_NATIVE_IF', 'IEM_MC_NATIVE_ELSE', 'IEM_MC_NATIVE_ENDIF' ),
2545 );
2546 def decodeCode(self, sRawCode, off = 0, offStop = -1, iLevel = 0): # pylint: disable=too-many-statements,too-many-branches
2547 """
2548 Decodes sRawCode[off : offStop].
2549
2550 Returns list of McStmt instances.
2551 Raises ParserException on failure.
2552 """
2553 if offStop < 0:
2554 offStop = len(sRawCode);
2555 aoStmts = [];
2556 while off < offStop:
2557 ch = sRawCode[off];
2558
2559 #
2560 # Skip spaces and comments.
2561 #
2562 if ch.isspace():
2563 off += 1;
2564
2565 elif ch == '/':
2566 ch = sRawCode[off + 1];
2567 if ch == '/': # C++ comment.
2568 off = sRawCode.find('\n', off + 2);
2569 if off < 0:
2570 break;
2571 off += 1;
2572 elif ch == '*': # C comment.
2573 off = sRawCode.find('*/', off + 2);
2574 if off < 0:
2575 break;
2576 off += 2;
2577 else:
2578 self.raiseDecodeError(sRawCode, off, 'Unexpected "/"');
2579
2580 #
2581 # Is it a MC statement.
2582 #
2583 elif ch == 'I' and sRawCode[off : off + len('IEM_MC_')] == 'IEM_MC_':
2584 # All MC statements ends with a semicolon, except for conditionals which ends with a '{'.
2585 # Extract it and strip comments from it.
2586 if self.isSubstrAt(sRawCode, off, self.kaasConditions[0][0]): iCond = 0;
2587 elif self.isSubstrAt(sRawCode, off, self.kaasConditions[1][0]): iCond = 1;
2588 else: iCond = -1;
2589 if iCond < 0:
2590 offEnd = sRawCode.find(';', off + len('IEM_MC_'));
2591 if offEnd <= off:
2592 self.raiseDecodeError(sRawCode, off, 'MC statement without a ";"');
2593 else:
2594 offEnd = sRawCode.find('{', off + len(self.kaasConditions[iCond][0]));
2595 if offEnd <= off:
2596 self.raiseDecodeError(sRawCode, off, 'MC conditional statement without a "{"');
2597 if sRawCode.find(';', off + len(self.kaasConditions[iCond][0]), offEnd) > off:
2598 self.raiseDecodeError(sRawCode, off, 'MC conditional statement without an immediate "{"');
2599 offEnd -= 1;
2600 while offEnd > off and sRawCode[offEnd - 1].isspace():
2601 offEnd -= 1;
2602
2603 sRawStmt = self.stripComments(sRawCode[off : offEnd]);
2604
2605 # Isolate the statement name.
2606 offOpenParen = sRawStmt.find('(');
2607 if offOpenParen < 0:
2608 self.raiseDecodeError(sRawCode, off, 'MC statement without a "("');
2609 sName = sRawStmt[: offOpenParen].strip();
2610
2611 # Extract the parameters.
2612 (asParams, offCloseParen) = self.extractParams(sRawStmt, offOpenParen);
2613 if asParams is None:
2614 self.raiseDecodeError(sRawCode, off, 'MC statement without a closing parenthesis');
2615 if offCloseParen + 1 != len(sRawStmt):
2616 self.raiseDecodeError(sRawCode, off,
2617 'Unexpected code following MC statement: %s' % (sRawStmt[offCloseParen + 1:]));
2618
2619 # Hand it to the handler.
2620 fnParser = g_dMcStmtParsers.get(sName);
2621 if not fnParser:
2622 self.raiseDecodeError(sRawCode, off, 'Unknown MC statement: %s' % (sName,));
2623 fnParser = fnParser[0];
2624 oStmt = fnParser(self, sName, asParams);
2625 if not isinstance(oStmt, (list, tuple)):
2626 aoStmts.append(oStmt);
2627 else:
2628 aoStmts.extend(oStmt);
2629
2630 #
2631 # If conditional, we need to parse the whole statement.
2632 #
2633 # For reasons of simplicity, we assume the following structure
2634 # and parse each branch in a recursive call:
2635 # IEM_MC_IF_XXX() {
2636 # IEM_MC_WHATEVER();
2637 # } IEM_MC_ELSE() {
2638 # IEM_MC_WHATEVER();
2639 # } IEM_MC_ENDIF();
2640 #
2641 if iCond >= 0:
2642 if iLevel > 1: ## @todo discount IEM_MC_NATIVE_IF.
2643 self.raiseDecodeError(sRawCode, off, 'Too deep nesting of conditionals.');
2644
2645 # Find start of the IF block:
2646 offBlock1 = self.skipSpacesAt(sRawCode, offEnd, offStop);
2647 if sRawCode[offBlock1] != '{':
2648 self.raiseDecodeError(sRawCode, offBlock1, 'Expected "{" following %s' % (sName,));
2649
2650 # Find the end of it.
2651 offBlock1End = self.findClosingBraces(sRawCode, offBlock1, offStop);
2652 if offBlock1End < 0:
2653 self.raiseDecodeError(sRawCode, offBlock1, 'No matching "}" closing IF block of %s' % (sName,));
2654
2655 oStmt.aoIfBranch = self.decodeCode(sRawCode, offBlock1 + 1, offBlock1End, iLevel + 1);
2656
2657 # Is there an else section?
2658 off = self.skipSpacesAt(sRawCode, offBlock1End + 1, offStop);
2659 sElseNm = self.kaasConditions[iCond][1];
2660 if self.isSubstrAt(sRawCode, off, sElseNm):
2661 off = self.skipSpacesAt(sRawCode, off + len(sElseNm), offStop);
2662 if sRawCode[off] != '(':
2663 self.raiseDecodeError(sRawCode, off, 'Expected "(" following %s"' % (sElseNm,));
2664 off = self.skipSpacesAt(sRawCode, off + 1, offStop);
2665 if sRawCode[off] != ')':
2666 self.raiseDecodeError(sRawCode, off, 'Expected ")" following %s("' % (sElseNm,));
2667
2668 # Find start of the ELSE block.
2669 offBlock2 = self.skipSpacesAt(sRawCode, off + 1, offStop);
2670 if sRawCode[offBlock2] != '{':
2671 self.raiseDecodeError(sRawCode, offBlock2, 'Expected "{" following %s()"' % (sElseNm,));
2672
2673 # Find the end of it.
2674 offBlock2End = self.findClosingBraces(sRawCode, offBlock2, offStop);
2675 if offBlock2End < 0:
2676 self.raiseDecodeError(sRawCode, offBlock2, 'No matching "}" closing ELSE block of %s' % (sName,));
2677
2678 oStmt.aoElseBranch = self.decodeCode(sRawCode, offBlock2 + 1, offBlock2End, iLevel + 1);
2679 off = self.skipSpacesAt(sRawCode, offBlock2End + 1, offStop);
2680
2681 # Parse past the endif statement.
2682 sEndIfNm = self.kaasConditions[iCond][2];
2683 if not self.isSubstrAt(sRawCode, off, sEndIfNm):
2684 self.raiseDecodeError(sRawCode, off, 'Expected %s for closing %s' % (sEndIfNm, sName,));
2685 off = self.skipSpacesAt(sRawCode, off + len(sEndIfNm), offStop);
2686 if sRawCode[off] != '(':
2687 self.raiseDecodeError(sRawCode, off, 'Expected "(" following %s"' % (sEndIfNm,));
2688 off = self.skipSpacesAt(sRawCode, off + 1, offStop);
2689 if sRawCode[off] != ')':
2690 self.raiseDecodeError(sRawCode, off, 'Expected ")" following %s("' % (sEndIfNm,));
2691 off = self.skipSpacesAt(sRawCode, off + 1, offStop);
2692 if sRawCode[off] != ';':
2693 self.raiseDecodeError(sRawCode, off, 'Expected ";" following %s()"' % (sEndIfNm,));
2694 off += 1;
2695
2696 else:
2697 # Advance.
2698 off = offEnd + 1;
2699
2700 #
2701 # Otherwise it must be a C/C++ statement of sorts.
2702 #
2703 else:
2704 # Find the end of the statement. if and else requires special handling.
2705 sCondExpr = None;
2706 oMatch = self.koReCppCtrlStmts.match(sRawCode, off);
2707 if oMatch:
2708 if oMatch.group(1)[-1] == '(':
2709 (sCondExpr, offEnd) = self.extractParam(sRawCode, oMatch.end());
2710 else:
2711 offEnd = oMatch.end();
2712 if not oMatch.group(1).startswith('if') and oMatch.group(1) != 'else':
2713 self.raiseDecodeError(sRawCode, off, 'Only if/else control statements allowed: %s' % (oMatch.group(1),));
2714 elif ch == '#':
2715 offEnd = sRawCode.find('\n', off, offStop);
2716 if offEnd < 0:
2717 offEnd = offStop;
2718 offEnd -= 1;
2719 while offEnd > off and sRawCode[offEnd - 1].isspace():
2720 offEnd -= 1;
2721 else:
2722 offEnd = sRawCode.find(';', off);
2723 if offEnd < 0:
2724 self.raiseDecodeError(sRawCode, off, 'C++ statement without a ";"');
2725
2726 # Check this and the following statement whether it might have
2727 # something to do with decoding. This is a statement filter
2728 # criteria when generating the threaded functions blocks.
2729 offNextEnd = sRawCode.find(';', offEnd + 1);
2730 fDecode = ( sRawCode.find('IEM_OPCODE_', off, max(offEnd, offNextEnd)) >= 0
2731 or sRawCode.find('IEMOP_HLP_DONE_', off, max(offEnd, offNextEnd)) >= 0
2732 or sRawCode.find('IEMOP_HLP_DECODED_', off, offEnd) >= 0
2733 or sRawCode.find('IEMOP_HLP_RAISE_UD_IF_MISSING_GUEST_FEATURE', off, offEnd) >= 0
2734 or sRawCode.find('IEMOP_HLP_VMX_INSTR', off, offEnd) >= 0
2735 or sRawCode.find('IEMOP_HLP_IN_VMX_OPERATION', off, offEnd) >= 0 ## @todo wrong
2736 );
2737
2738 if not oMatch:
2739 if ch != '#':
2740 aoStmts.append(McCppGeneric(sRawCode[off : offEnd + 1], fDecode));
2741 else:
2742 aoStmts.append(McCppPreProc(sRawCode[off : offEnd + 1]));
2743 off = offEnd + 1;
2744 elif oMatch.group(1).startswith('if'):
2745 #
2746 # if () xxx [else yyy] statement.
2747 #
2748 oStmt = McCppCond(sCondExpr, fDecode);
2749 aoStmts.append(oStmt);
2750 off = offEnd + 1;
2751
2752 # Following the if () we can either have a {} containing zero or more statements
2753 # or we have a single statement.
2754 offBlock1 = self.skipSpacesAt(sRawCode, offEnd + 1, offStop);
2755 if sRawCode[offBlock1] == '{':
2756 offBlock1End = self.findClosingBraces(sRawCode, offBlock1, offStop);
2757 if offBlock1End < 0:
2758 self.raiseDecodeError(sRawCode, offBlock1, 'No matching "}" closing if block');
2759 offBlock1 += 1;
2760 else:
2761 offBlock1End = sRawCode.find(';', offBlock1, offStop);
2762 if offBlock1End < 0:
2763 self.raiseDecodeError(sRawCode, off, 'Expected ";" terminating one-line if block"');
2764
2765 oStmt.aoIfBranch = self.decodeCode(sRawCode, offBlock1, offBlock1End, iLevel + 1);
2766
2767 # The else is optional and can likewise be followed by {} or a single statement.
2768 off = self.skipSpacesAt(sRawCode, offBlock1End + 1, offStop);
2769 if self.isSubstrAt(sRawCode, off, 'else') and sRawCode[off + len('else')].isspace():
2770 offBlock2 = self.skipSpacesAt(sRawCode, off + len('else'), offStop);
2771 if sRawCode[offBlock2] == '{':
2772 offBlock2End = self.findClosingBraces(sRawCode, offBlock2, offStop);
2773 if offBlock2End < 0:
2774 self.raiseDecodeError(sRawCode, offBlock2, 'No matching "}" closing else block');
2775 offBlock2 += 1;
2776 else:
2777 offBlock2End = sRawCode.find(';', offBlock2, offStop);
2778 if offBlock2End < 0:
2779 self.raiseDecodeError(sRawCode, off, 'Expected ";" terminating one-line else block"');
2780
2781 oStmt.aoElseBranch = self.decodeCode(sRawCode, offBlock2, offBlock2End, iLevel + 1);
2782 off = offBlock2End + 1;
2783
2784 elif oMatch.group(1) == 'else':
2785 # Problematic 'else' branch, typically involving #ifdefs.
2786 self.raiseDecodeError(sRawCode, off, 'Mixed up else/#ifdef or something confusing us.');
2787
2788 return aoStmts;
2789
2790 def decode(self):
2791 """
2792 Decodes the block, populating self.aoStmts if necessary.
2793 Returns the statement list.
2794 Raises ParserException on failure.
2795 """
2796 if not self.aoStmts:
2797 self.aoStmts = self.decodeCode(''.join(self.asLines));
2798 return self.aoStmts;
2799
2800
2801 def checkForTooEarlyEffSegUse(self, aoStmts):
2802 """
2803 Checks if iEffSeg is used before the effective address has been decoded.
2804 Returns None on success, error string on failure.
2805
2806 See r158454 for an example of this issue.
2807 """
2808
2809 # Locate the IEM_MC_CALC_RM_EFF_ADDR statement, if found, scan backwards
2810 # for IEMCPU::iEffSeg references. No need to check conditional branches,
2811 # as we're ASSUMING these will not occur before address calculation.
2812 for iStmt, oStmt in enumerate(aoStmts):
2813 if oStmt.sName == 'IEM_MC_CALC_RM_EFF_ADDR':
2814 while iStmt > 0:
2815 iStmt -= 1;
2816 oStmt = aoStmts[iStmt];
2817 for sArg in oStmt.asParams:
2818 if sArg.find('pVCpu->iem.s.iEffSeg') >= 0:
2819 return "statement #%u: pVCpu->iem.s.iEffSeg is used prior to IEM_MC_CALC_RM_EFF_ADDR!" % (iStmt + 1,);
2820 break;
2821 return None;
2822
2823 koReCppFirstWord = re.compile(r'^\s*(\w+)[ (;]');
2824 kdDecodeCppStmtOkayAfterDone = {
2825 'IEMOP_HLP_IN_VMX_OPERATION': True,
2826 'IEMOP_HLP_VMX_INSTR': True,
2827 };
2828
2829 def checkForDoneDecoding(self, aoStmts):
2830 """
2831 Checks that the block contains a IEMOP_HLP_DONE_*DECODING* macro
2832 invocation.
2833 Returns None on success, error string on failure.
2834
2835 This ensures safe instruction restarting in case the recompiler runs
2836 out of TB resources during recompilation (e.g. aRanges or aGCPhysPages
2837 entries).
2838 """
2839
2840 # The IEMOP_HLP_DONE_ stuff is not allowed inside conditionals, so we
2841 # don't need to look.
2842 cIemOpHlpDone = 0;
2843 for iStmt, oStmt in enumerate(aoStmts):
2844 if oStmt.isCppStmt():
2845 #print('dbg: #%u[%u]: %s %s (%s)'
2846 # % (iStmt + 1, cIemOpHlpDone, oStmt.sName, 'd' if oStmt.fDecode else 'r', oStmt.asParams[0],));
2847
2848 oMatch = self.koReCppFirstWord.match(oStmt.asParams[0]);
2849 if oMatch:
2850 sFirstWord = oMatch.group(1);
2851 if ( sFirstWord.startswith('IEMOP_HLP_DONE_')
2852 or sFirstWord.startswith('IEMOP_HLP_DECODED_')):
2853 cIemOpHlpDone += 1;
2854 elif cIemOpHlpDone > 0 and oStmt.fDecode and sFirstWord not in self.kdDecodeCppStmtOkayAfterDone:
2855 return "statement #%u: Decoding statement following IEMOP_HLP_DONE_*DECODING*!" % (iStmt + 1,);
2856 #else: print('dbg: #%u[%u]: %s' % (iStmt + 1, cIemOpHlpDone, oStmt.asParams[0]));
2857 else:
2858 #print('dbg: #%u[%u]: %s' % (iStmt + 1, cIemOpHlpDone, oStmt.sName));
2859 if oStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_') and iStmt == 0: # implicit
2860 cIemOpHlpDone += 1;
2861 elif cIemOpHlpDone == 0 and g_dMcStmtParsers.get(oStmt.sName, (None, False))[1]:
2862 return "statement #%u: State modifying MC statement before IEMOP_HLP_DONE_*DECODING*!" % (iStmt + 1,);
2863 elif cIemOpHlpDone > 0 and oStmt.sName in ('IEM_MC_CALC_RM_EFF_ADDR',):
2864 return "statement #%u: Decoding statement following IEMOP_HLP_DONE_*DECODING*!" % (iStmt + 1,);
2865 if cIemOpHlpDone == 1:
2866 return None;
2867 if cIemOpHlpDone > 1:
2868 return "Block has more than one IEMOP_HLP_DONE_*DECODING* invocation!";
2869 return "Block is missing IEMOP_HLP_DONE_*DECODING* invocation!";
2870
2871 def checkForFetchAfterRef(self, aoStmts, asRegRefClasses):
2872 """
2873 Checks that the register references are placed after register fetches
2874 from the same register class.
2875 Returns None on success, error string on failure.
2876
2877 Example:
2878 SHL CH, CL
2879
2880 If the CH reference is created first, the fetching of CL will cause the
2881 RCX guest register to have an active shadow register when it's being
2882 updated. The shadow register will then be stale after the SHL operation
2883 completes, without us noticing.
2884
2885 It's easier to ensure we've got correct code than complicating the
2886 recompiler code with safeguards here.
2887 """
2888 for iStmt, oStmt in enumerate(aoStmts):
2889 if not oStmt.isCppStmt():
2890 offRef = oStmt.sName.find("_REF_");
2891 if offRef > 0:
2892 if oStmt.sName in ('IEM_MC_IF_FPUREG_NOT_EMPTY_REF_R80',
2893 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80',
2894 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80_FIRST',):
2895 sClass = 'FPUREG';
2896 else:
2897 offUnderscore = oStmt.sName.find('_', offRef + 5);
2898 if offUnderscore > 0:
2899 assert offUnderscore > offRef;
2900 sClass = oStmt.sName[offRef + 5 : offUnderscore];
2901 else:
2902 sClass = oStmt.sName[offRef + 5];
2903 asRegRefClasses[sClass] = True;
2904 else:
2905 offFetch = oStmt.sName.find("_FETCH_");
2906 if offFetch > 0:
2907 sClass = oStmt.sName[offFetch + 7 : ];
2908 if not sClass.startswith("MEM"):
2909 offUnderscore = sClass.find('_');
2910 if offUnderscore >= 0:
2911 assert offUnderscore > 0;
2912 sClass = sClass[:offUnderscore];
2913 if sClass in asRegRefClasses:
2914 return "statement #%u: %s following REF! That'll mess up guest register shadowing" \
2915 % (iStmt + 1, oStmt.sName,);
2916
2917 # Go into branches.
2918 if isinstance(oStmt, McStmtCond):
2919 sRet = self.checkForFetchAfterRef(oStmt.aoIfBranch, asRegRefClasses);
2920 if sRet:
2921 return sRet;
2922 sRet = self.checkForFetchAfterRef(oStmt.aoElseBranch, asRegRefClasses);
2923 if sRet:
2924 return sRet;
2925 return None;
2926
2927 koReRefEflIllegalMemRough = re.compile(r'^IEM_MC_.*(MEM|PUSH_U|POP_GREG|RETN|IND_CALL|REL_CALL)');
2928 koReRefEflIllegalMemExclude = re.compile(r'^IEM_MC_.*(MEM_COMMIT|MEM_OP|FPU_|UPDATE_FSW)');
2929 koReRefEflIllegalRaise = re.compile(r'^IEM_MC_(RAISE|MAYBE_RAISE)');
2930
2931 def checkRefEFlagsUse(self, aoStmts, asState):
2932 """
2933 Checks that EFLAGS references comes after memory fetches and that there
2934 are no memory stores or conditional raises afterwards.
2935
2936 The problem is postponed EFLAGS calculation management. This gets a
2937 lot easier if we can jettison any postponements when EFLAGS are
2938 referenced. If we had to deal with potential TB exits / exceptions
2939 after they are referenced, this means it would have to delay the
2940 cleanup until the IEM_MC_..._AND_FINISH statement which is kind of
2941 complicated and not very efficient.
2942 """
2943 fSeenIt = asState.get('fSeenIt', False);
2944 for iStmt, oStmt in enumerate(aoStmts):
2945 if not oStmt.isCppStmt():
2946 if oStmt.sName in ('IEM_MC_REF_EFLAGS', 'IEM_MC_REF_EFLAGS_EX',):
2947 fSeenIt = True;
2948 elif ( fSeenIt
2949 and ( ( self.koReRefEflIllegalMemRough.match(oStmt.sName)
2950 and not self.koReRefEflIllegalMemExclude.match(oStmt.sName))
2951 or self.koReRefEflIllegalRaise.match(oStmt.sName) )):
2952 return "statement #%u: %s following REF_EFLAGS! That'll mess up EFLAGS calculation postponing" \
2953 % (iStmt + 1, oStmt.sName,);
2954
2955 # Go into branches.
2956 if isinstance(oStmt, McStmtCond):
2957 asState['fSeenIt'] = fSeenIt;
2958 sRet = self.checkRefEFlagsUse(oStmt.aoIfBranch, asState);
2959 if sRet:
2960 return sRet;
2961 sRet = self.checkRefEFlagsUse(oStmt.aoElseBranch, asState);
2962 if sRet:
2963 return sRet;
2964 fSeenIt = asState['fSeenIt'];
2965 return None;
2966
2967 def check(self):
2968 """
2969 Performs some sanity checks on the block.
2970 Returns error string list, empty if all is fine.
2971 """
2972 aoStmts = self.decode();
2973 asRet = [];
2974
2975 sRet = self.checkForTooEarlyEffSegUse(aoStmts);
2976 if sRet:
2977 asRet.append(sRet);
2978
2979 sRet = self.checkForDoneDecoding(aoStmts);
2980 if sRet:
2981 asRet.append(sRet);
2982
2983 sRet = self.checkForFetchAfterRef(aoStmts, {});
2984 if sRet:
2985 asRet.append(sRet);
2986
2987 sRet = self.checkRefEFlagsUse(aoStmts, {});
2988 if sRet:
2989 asRet.append(sRet);
2990
2991 return asRet;
2992
2993
2994## Temporary flag for enabling / disabling experimental MCs depending on the
2995## SIMD register allocator.
2996g_fNativeSimd = True;
2997
2998## IEM_MC_XXX -> parser + info dictionary.
2999#
3000# The info columns:
3001# - col 1+0: boolean entry indicating whether the statement modifies state and
3002# must not be used before IEMOP_HL_DONE_*.
3003# - col 1+1: boolean entry indicating similar to the previous column but is
3004# used to decide when to emit calls for conditional jumps (Jmp/NoJmp).
3005# The difference is that most IEM_MC_IF_XXX entries are False here.
3006# - col 1+2: boolean entry indicating native recompiler support.
3007#
3008# The raw table was generated via the following command
3009# sed -n -e "s/^# *define *\(IEM_MC_[A-Z_0-9]*\)[ (].*$/ '\1': McBlock.parseMcGeneric,/p" include/IEMMc.h \
3010# | sort | uniq | gawk "{printf """ %%-60s (%%s, True)\n""", $1, $2}"
3011# pylint: disable=line-too-long
3012g_dMcStmtParsers = {
3013 'IEM_MC_ACTUALIZE_AVX_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, True, ),
3014 'IEM_MC_ACTUALIZE_AVX_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, True, ),
3015 'IEM_MC_ACTUALIZE_FPU_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, True, ),
3016 'IEM_MC_ACTUALIZE_FPU_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, True, ),
3017 'IEM_MC_ACTUALIZE_SSE_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, True, ),
3018 'IEM_MC_ACTUALIZE_SSE_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, True, ),
3019 'IEM_MC_ADD_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3020 'IEM_MC_ADD_GREG_U16_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
3021 'IEM_MC_ADD_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3022 'IEM_MC_ADD_GREG_U32_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
3023 'IEM_MC_ADD_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3024 'IEM_MC_ADD_GREG_U64_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
3025 'IEM_MC_ADD_GREG_U8_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
3026 'IEM_MC_ADD_LOCAL_S16_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, True, True, ),
3027 'IEM_MC_ADD_LOCAL_S32_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, True, True, ),
3028 'IEM_MC_ADD_LOCAL_S64_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, True, True, ),
3029 'IEM_MC_ADVANCE_RIP_AND_FINISH': (McBlock.parseMcGeneric, True, True, True, ),
3030 'IEM_MC_AND_2LOCS_U32': (McBlock.parseMcGeneric, False, False, False, ),
3031 'IEM_MC_AND_ARG_U16': (McBlock.parseMcGeneric, False, False, True, ),
3032 'IEM_MC_AND_ARG_U32': (McBlock.parseMcGeneric, False, False, True, ),
3033 'IEM_MC_AND_ARG_U64': (McBlock.parseMcGeneric, False, False, True, ),
3034 'IEM_MC_AND_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3035 'IEM_MC_AND_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3036 'IEM_MC_AND_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3037 'IEM_MC_AND_GREG_U8': (McBlock.parseMcGeneric, True, True, True, ),
3038 'IEM_MC_AND_LOCAL_U16': (McBlock.parseMcGeneric, False, False, True, ),
3039 'IEM_MC_AND_LOCAL_U32': (McBlock.parseMcGeneric, False, False, True, ),
3040 'IEM_MC_AND_LOCAL_U64': (McBlock.parseMcGeneric, False, False, True, ),
3041 'IEM_MC_AND_LOCAL_U8': (McBlock.parseMcGeneric, False, False, True, ),
3042 'IEM_MC_ARG': (McBlock.parseMcArg, False, False, True, ),
3043 'IEM_MC_ARG_CONST': (McBlock.parseMcArgConst, False, False, True, ),
3044 'IEM_MC_ARG_EFLAGS': (McBlock.parseMcArgEFlags, False, False, True, ),
3045 'IEM_MC_ARG_LOCAL_EFLAGS': (McBlock.parseMcArgLocalEFlags, False, False, True, ),
3046 'IEM_MC_ARG_LOCAL_REF': (McBlock.parseMcArgLocalRef, False, False, True, ),
3047 'IEM_MC_ASSIGN_TO_SMALLER': (McBlock.parseMcGeneric, False, False, True, ),
3048 'IEM_MC_BEGIN': (McBlock.parseMcBegin, False, False, True, ),
3049 'IEM_MC_BROADCAST_XREG_U16_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3050 'IEM_MC_BROADCAST_XREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3051 'IEM_MC_BROADCAST_XREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3052 'IEM_MC_BROADCAST_XREG_U8_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3053 'IEM_MC_BROADCAST_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3054 'IEM_MC_BROADCAST_YREG_U16_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3055 'IEM_MC_BROADCAST_YREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3056 'IEM_MC_BROADCAST_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3057 'IEM_MC_BROADCAST_YREG_U8_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3058 'IEM_MC_BSWAP_LOCAL_U16': (McBlock.parseMcGeneric, False, False, True, ),
3059 'IEM_MC_BSWAP_LOCAL_U32': (McBlock.parseMcGeneric, False, False, True, ),
3060 'IEM_MC_BSWAP_LOCAL_U64': (McBlock.parseMcGeneric, False, False, True, ),
3061 'IEM_MC_CALC_RM_EFF_ADDR': (McBlock.parseMcGeneric, False, False, False, ),
3062 'IEM_MC_CALL_AIMPL_3': (McBlock.parseMcCallAImpl, True, True, True, ),
3063 'IEM_MC_CALL_AIMPL_4': (McBlock.parseMcCallAImpl, True, True, True, ),
3064 'IEM_MC_CALL_AVX_AIMPL_2': (McBlock.parseMcCallAvxAImpl, True, True, g_fNativeSimd),
3065 'IEM_MC_CALL_AVX_AIMPL_3': (McBlock.parseMcCallAvxAImpl, True, True, g_fNativeSimd),
3066 'IEM_MC_CALL_CIMPL_0': (McBlock.parseMcCallCImpl, True, True, False, ),
3067 'IEM_MC_CALL_CIMPL_1': (McBlock.parseMcCallCImpl, True, True, False, ),
3068 'IEM_MC_CALL_CIMPL_2': (McBlock.parseMcCallCImpl, True, True, False, ),
3069 'IEM_MC_CALL_CIMPL_3': (McBlock.parseMcCallCImpl, True, True, False, ),
3070 'IEM_MC_CALL_CIMPL_4': (McBlock.parseMcCallCImpl, True, True, False, ),
3071 'IEM_MC_CALL_CIMPL_5': (McBlock.parseMcCallCImpl, True, True, False, ),
3072 'IEM_MC_CALL_FPU_AIMPL_1': (McBlock.parseMcCallFpuAImpl, True, True, False, ),
3073 'IEM_MC_CALL_FPU_AIMPL_2': (McBlock.parseMcCallFpuAImpl, True, True, False, ),
3074 'IEM_MC_CALL_FPU_AIMPL_3': (McBlock.parseMcCallFpuAImpl, True, True, False, ),
3075 'IEM_MC_CALL_MMX_AIMPL_2': (McBlock.parseMcCallMmxAImpl, True, True, False, ),
3076 'IEM_MC_CALL_MMX_AIMPL_3': (McBlock.parseMcCallMmxAImpl, True, True, False, ),
3077 'IEM_MC_CALL_SSE_AIMPL_2': (McBlock.parseMcCallSseAImpl, True, True, g_fNativeSimd),
3078 'IEM_MC_CALL_SSE_AIMPL_3': (McBlock.parseMcCallSseAImpl, True, True, g_fNativeSimd),
3079 'IEM_MC_CALL_VOID_AIMPL_0': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
3080 'IEM_MC_CALL_VOID_AIMPL_1': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
3081 'IEM_MC_CALL_VOID_AIMPL_2': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
3082 'IEM_MC_CALL_VOID_AIMPL_3': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
3083 'IEM_MC_CALL_VOID_AIMPL_4': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
3084 'IEM_MC_CLEAR_EFL_BIT': (McBlock.parseMcGeneric, True, True, True, ),
3085 'IEM_MC_CLEAR_FSW_EX': (McBlock.parseMcGeneric, True, True, False, ),
3086 'IEM_MC_CLEAR_HIGH_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3087 'IEM_MC_CLEAR_XREG_U32_MASK': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3088 'IEM_MC_CLEAR_YREG_128_UP': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3089 'IEM_MC_CLEAR_ZREG_256_UP': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3090 'IEM_MC_COMMIT_EFLAGS': (McBlock.parseMcGeneric, True, True, True, ),
3091 'IEM_MC_COMMIT_EFLAGS_OPT': (McBlock.parseMcGeneric, True, True, True, ),
3092 'IEM_MC_COPY_XREG_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3093 'IEM_MC_COPY_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3094 'IEM_MC_COPY_YREG_U256_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3095 'IEM_MC_COPY_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3096 'IEM_MC_DEFER_TO_CIMPL_0_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
3097 'IEM_MC_DEFER_TO_CIMPL_1_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
3098 'IEM_MC_DEFER_TO_CIMPL_2_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
3099 'IEM_MC_DEFER_TO_CIMPL_3_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
3100 'IEM_MC_END': (McBlock.parseMcGeneric, True, True, True, ),
3101 'IEM_MC_FETCH_EFLAGS': (McBlock.parseMcGeneric, False, False, True, ),
3102 'IEM_MC_FETCH_EFLAGS_U8': (McBlock.parseMcGeneric, False, False, False, ),
3103 'IEM_MC_FETCH_FCW': (McBlock.parseMcGeneric, False, False, True, ),
3104 'IEM_MC_FETCH_FSW': (McBlock.parseMcGeneric, False, False, True, ),
3105 'IEM_MC_FETCH_GREG_I16': (McBlock.parseMcGeneric, False, False, True, ),
3106 'IEM_MC_FETCH_GREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
3107 'IEM_MC_FETCH_GREG_U16_SX_U32': (McBlock.parseMcGeneric, False, False, True, ),
3108 'IEM_MC_FETCH_GREG_U16_SX_U64': (McBlock.parseMcGeneric, False, False, True, ),
3109 'IEM_MC_FETCH_GREG_U16_ZX_U32': (McBlock.parseMcGeneric, False, False, True, ),
3110 'IEM_MC_FETCH_GREG_U16_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
3111 'IEM_MC_FETCH_GREG_I32': (McBlock.parseMcGeneric, False, False, True, ),
3112 'IEM_MC_FETCH_GREG_U32': (McBlock.parseMcGeneric, False, False, True, ),
3113 'IEM_MC_FETCH_GREG_U32_SX_U64': (McBlock.parseMcGeneric, False, False, True, ),
3114 'IEM_MC_FETCH_GREG_U32_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
3115 'IEM_MC_FETCH_GREG_U64': (McBlock.parseMcGeneric, False, False, True, ),
3116 'IEM_MC_FETCH_GREG_U64_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
3117 'IEM_MC_FETCH_GREG_U8': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
3118 'IEM_MC_FETCH_GREG_U8_SX_U16': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
3119 'IEM_MC_FETCH_GREG_U8_SX_U32': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
3120 'IEM_MC_FETCH_GREG_U8_SX_U64': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
3121 'IEM_MC_FETCH_GREG_U8_ZX_U16': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
3122 'IEM_MC_FETCH_GREG_U8_ZX_U32': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
3123 'IEM_MC_FETCH_GREG_U8_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
3124 'IEM_MC_FETCH_GREG_PAIR_U32': (McBlock.parseMcGeneric, False, False, False, ),
3125 'IEM_MC_FETCH_GREG_PAIR_U64': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3126 'IEM_MC_FETCH_MEM_D80': (McBlock.parseMcGeneric, True, True, False, ),
3127 'IEM_MC_FETCH_MEM_I16': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3128 'IEM_MC_FETCH_MEM_I16_DISP': (McBlock.parseMcGeneric, True, True, True, ),
3129 'IEM_MC_FETCH_MEM_I32': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3130 'IEM_MC_FETCH_MEM_I32_DISP': (McBlock.parseMcGeneric, True, True, True, ),
3131 'IEM_MC_FETCH_MEM_I64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3132 'IEM_MC_FETCH_MEM_R32': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3133 'IEM_MC_FETCH_MEM_R64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3134 'IEM_MC_FETCH_MEM_R80': (McBlock.parseMcGeneric, True, True, False, ),
3135 'IEM_MC_FETCH_MEM_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3136 'IEM_MC_FETCH_MEM_U128_ALIGN_SSE': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3137 'IEM_MC_FETCH_MEM_U128_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3138 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128': (McBlock.parseMcGeneric, True, True, False, ),
3139 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_RAX_RDX_U64': (McBlock.parseMcGeneric, True, True, False, ),
3140 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_EAX_EDX_U32_SX_U64':(McBlock.parseMcGeneric, True, True, False, ),
3141 'IEM_MC_FETCH_MEM_U16': (McBlock.parseMcGeneric, True, True, True, ),
3142 'IEM_MC_FETCH_MEM_U16_DISP': (McBlock.parseMcGeneric, True, True, True, ),
3143 'IEM_MC_FETCH_MEM_U16_SX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movsx
3144 'IEM_MC_FETCH_MEM_U16_SX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movsx
3145 'IEM_MC_FETCH_MEM_U16_ZX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movzx
3146 'IEM_MC_FETCH_MEM_U16_ZX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movzx
3147 'IEM_MC_FETCH_MEM_U256': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3148 'IEM_MC_FETCH_MEM_U256_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3149 'IEM_MC_FETCH_MEM_U256_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3150 'IEM_MC_FETCH_MEM_U32': (McBlock.parseMcGeneric, True, True, True, ),
3151 'IEM_MC_FETCH_MEM_U32_DISP': (McBlock.parseMcGeneric, True, True, True, ), #bounds only
3152 'IEM_MC_FETCH_MEM_U32_SX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movsx
3153 'IEM_MC_FETCH_MEM_U32_ZX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movzx
3154 'IEM_MC_FETCH_MEM_U64': (McBlock.parseMcGeneric, True, True, True, ),
3155 'IEM_MC_FETCH_MEM_U64_ALIGN_U128': (McBlock.parseMcGeneric, True, True, False, ),
3156 'IEM_MC_FETCH_MEM_U8': (McBlock.parseMcGeneric, True, True, True, ),
3157 'IEM_MC_FETCH_MEM_U8_SX_U16': (McBlock.parseMcGeneric, True, True, True, ), # movsx
3158 'IEM_MC_FETCH_MEM_U8_SX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movsx
3159 'IEM_MC_FETCH_MEM_U8_SX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movsx
3160 'IEM_MC_FETCH_MEM_U8_ZX_U16': (McBlock.parseMcGeneric, True, True, True, ), # movzx
3161 'IEM_MC_FETCH_MEM_U8_ZX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movzx
3162 'IEM_MC_FETCH_MEM_U8_ZX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movzx
3163 'IEM_MC_FETCH_MEM_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3164 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3165 'IEM_MC_FETCH_MEM_XMM_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3166 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3167 'IEM_MC_FETCH_MEM_XMM_NO_AC_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3168 'IEM_MC_FETCH_MEM_XMM_U32_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3169 'IEM_MC_FETCH_MEM_XMM_U64_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3170 'IEM_MC_FETCH_MEM_YMM': (McBlock.parseMcGeneric, True, True, False, ),
3171 'IEM_MC_FETCH_MEM_YMM_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, False, ),
3172 'IEM_MC_FETCH_MEM_YMM_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3173 'IEM_MC_FETCH_MEM_YMM_NO_AC_AND_YREG_YMM': (McBlock.parseMcGeneric, True, True, False, ),
3174 'IEM_MC_FETCH_MEM16_U8': (McBlock.parseMcGeneric, True, True, False, ),
3175 'IEM_MC_FETCH_MEM32_U8': (McBlock.parseMcGeneric, True, True, False, ),
3176 'IEM_MC_FETCH_MREG_U8': (McBlock.parseMcGeneric, False, False, False, ),
3177 'IEM_MC_FETCH_MREG_U16': (McBlock.parseMcGeneric, False, False, False, ),
3178 'IEM_MC_FETCH_MREG_U32': (McBlock.parseMcGeneric, False, False, False, ),
3179 'IEM_MC_FETCH_MREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
3180 'IEM_MC_FETCH_SREG_BASE_U32': (McBlock.parseMcGeneric, False, False, False, ),
3181 'IEM_MC_FETCH_SREG_BASE_U64': (McBlock.parseMcGeneric, False, False, False, ),
3182 'IEM_MC_FETCH_SREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
3183 'IEM_MC_FETCH_SREG_ZX_U32': (McBlock.parseMcGeneric, False, False, True, ),
3184 'IEM_MC_FETCH_SREG_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
3185 'IEM_MC_FETCH_XREG_R32': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3186 'IEM_MC_FETCH_XREG_R64': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3187 'IEM_MC_FETCH_XREG_U128': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3188 'IEM_MC_FETCH_XREG_U16': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3189 'IEM_MC_FETCH_XREG_U32': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3190 'IEM_MC_FETCH_XREG_U64': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3191 'IEM_MC_FETCH_XREG_U8': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3192 'IEM_MC_FETCH_XREG_XMM': (McBlock.parseMcGeneric, False, False, False, ),
3193 'IEM_MC_FETCH_XREG_PAIR_U128': (McBlock.parseMcGeneric, False, False, False, ),
3194 'IEM_MC_FETCH_XREG_PAIR_U128_AND_RAX_RDX_U64': (McBlock.parseMcGeneric, False, False, False, ),
3195 'IEM_MC_FETCH_XREG_PAIR_U128_AND_EAX_EDX_U32_SX_U64': (McBlock.parseMcGeneric, False, False, False, ),
3196 'IEM_MC_FETCH_XREG_PAIR_XMM': (McBlock.parseMcGeneric, False, False, False, ),
3197 'IEM_MC_FETCH_YREG_U128': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3198 'IEM_MC_FETCH_YREG_U256': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3199 'IEM_MC_FETCH_YREG_YMM': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3200 'IEM_MC_FETCH_YREG_U32': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3201 'IEM_MC_FETCH_YREG_U64': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3202 'IEM_MC_FETCH_YREG_PAIR_YMM': (McBlock.parseMcGeneric, False, False, False, ),
3203 'IEM_MC_FLIP_EFL_BIT': (McBlock.parseMcGeneric, True, True, True, ),
3204 'IEM_MC_FPU_FROM_MMX_MODE': (McBlock.parseMcGeneric, True, True, False, ),
3205 'IEM_MC_FPU_STACK_DEC_TOP': (McBlock.parseMcGeneric, True, True, False, ),
3206 'IEM_MC_FPU_STACK_FREE': (McBlock.parseMcGeneric, True, True, False, ),
3207 'IEM_MC_FPU_STACK_INC_TOP': (McBlock.parseMcGeneric, True, True, False, ),
3208 'IEM_MC_FPU_STACK_PUSH_OVERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
3209 'IEM_MC_FPU_STACK_PUSH_OVERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3210 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
3211 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW_TWO': (McBlock.parseMcGeneric, True, True, False, ),
3212 'IEM_MC_FPU_STACK_UNDERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
3213 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3214 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3215 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3216 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP_POP': (McBlock.parseMcGeneric, True, True, False, ),
3217 'IEM_MC_FPU_TO_MMX_MODE': (McBlock.parseMcGeneric, True, True, False, ),
3218 'IEM_MC_HINT_FLUSH_GUEST_SHADOW': (McBlock.parseMcGeneric, True, True, True, ),
3219 'IEM_MC_IF_CX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
3220 'IEM_MC_IF_CX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
3221 'IEM_MC_IF_CX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3222 'IEM_MC_IF_CX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3223 'IEM_MC_IF_ECX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
3224 'IEM_MC_IF_ECX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
3225 'IEM_MC_IF_ECX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3226 'IEM_MC_IF_ECX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3227 'IEM_MC_IF_EFL_ANY_BITS_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3228 'IEM_MC_IF_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3229 'IEM_MC_IF_EFL_BIT_NOT_SET_AND_BITS_EQ': (McBlock.parseMcGenericCond, True, False, True, ),
3230 'IEM_MC_IF_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3231 'IEM_MC_IF_EFL_BIT_SET_OR_BITS_NE': (McBlock.parseMcGenericCond, True, False, True, ),
3232 'IEM_MC_IF_EFL_BITS_EQ': (McBlock.parseMcGenericCond, True, False, True, ),
3233 'IEM_MC_IF_EFL_BITS_NE': (McBlock.parseMcGenericCond, True, False, True, ),
3234 'IEM_MC_IF_EFL_NO_BITS_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3235 'IEM_MC_IF_FCW_IM': (McBlock.parseMcGenericCond, True, True, False, ),
3236 'IEM_MC_IF_FPUREG_IS_EMPTY': (McBlock.parseMcGenericCond, True, True, False, ),
3237 'IEM_MC_IF_FPUREG_NOT_EMPTY': (McBlock.parseMcGenericCond, True, True, False, ),
3238 'IEM_MC_IF_FPUREG_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, True, False, ),
3239 'IEM_MC_IF_GREG_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3240 'IEM_MC_IF_LOCAL_IS_Z': (McBlock.parseMcGenericCond, True, False, True, ),
3241 'IEM_MC_IF_RCX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
3242 'IEM_MC_IF_RCX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
3243 'IEM_MC_IF_RCX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3244 'IEM_MC_IF_RCX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3245 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, True, False, ),
3246 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80_FIRST': (McBlock.parseMcGenericCond, True, True, False, ),
3247 'IEM_MC_IND_CALL_U16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3248 'IEM_MC_IND_CALL_U32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3249 'IEM_MC_IND_CALL_U64_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3250 'IEM_MC_INT_CLEAR_ZMM_256_UP': (McBlock.parseMcGeneric, True, True, False, ),
3251 'IEM_MC_LIVENESS_GREG_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3252 'IEM_MC_LIVENESS_GREG_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3253 'IEM_MC_LIVENESS_GREG_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3254 'IEM_MC_LIVENESS_MREG_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3255 'IEM_MC_LIVENESS_MREG_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3256 'IEM_MC_LIVENESS_MREG_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3257 'IEM_MC_LIVENESS_XREG_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3258 'IEM_MC_LIVENESS_XREG_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3259 'IEM_MC_LIVENESS_XREG_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3260 'IEM_MC_LIVENESS_MXCSR_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3261 'IEM_MC_LIVENESS_MXCSR_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3262 'IEM_MC_LIVENESS_MXCSR_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3263 'IEM_MC_LOCAL': (McBlock.parseMcLocal, False, False, True, ),
3264 'IEM_MC_LOCAL_ASSIGN': (McBlock.parseMcLocalAssign, False, False, True, ),
3265 'IEM_MC_LOCAL_CONST': (McBlock.parseMcLocalConst, False, False, True, ),
3266 'IEM_MC_LOCAL_EFLAGS': (McBlock.parseMcLocalEFlags, True, True, True, ),
3267 'IEM_MC_NOREF': (McBlock.parseMcGeneric, False, False, True, ),
3268 'IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, True, ),
3269 'IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, True, True, ),
3270 'IEM_MC_MAYBE_RAISE_FPU_XCPT': (McBlock.parseMcGeneric, True, True, True, ),
3271 'IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3272 'IEM_MC_MAYBE_RAISE_MMX_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3273 'IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0': (McBlock.parseMcGeneric, True, True, False, ),
3274 'IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, True, ),
3275 'IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, True, True, ),
3276 'IEM_MC_MEM_COMMIT_AND_UNMAP_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3277 'IEM_MC_MEM_COMMIT_AND_UNMAP_RW': (McBlock.parseMcGeneric, True, True, True, ),
3278 'IEM_MC_MEM_COMMIT_AND_UNMAP_RO': (McBlock.parseMcGeneric, True, True, True, ),
3279 'IEM_MC_MEM_COMMIT_AND_UNMAP_WO': (McBlock.parseMcGeneric, True, True, True, ),
3280 'IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE_WO': (McBlock.parseMcGeneric, True, True, False, ),
3281 'IEM_MC_MEM_MAP_D80_WO': (McBlock.parseMcGeneric, True, True, True, ),
3282 'IEM_MC_MEM_MAP_I16_WO': (McBlock.parseMcGeneric, True, True, True, ),
3283 'IEM_MC_MEM_MAP_I32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3284 'IEM_MC_MEM_MAP_I64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3285 'IEM_MC_MEM_MAP_R32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3286 'IEM_MC_MEM_MAP_R64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3287 'IEM_MC_MEM_MAP_R80_WO': (McBlock.parseMcGeneric, True, True, True, ),
3288 'IEM_MC_MEM_MAP_U8_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3289 'IEM_MC_MEM_MAP_U8_RW': (McBlock.parseMcGeneric, True, True, True, ),
3290 'IEM_MC_MEM_MAP_U8_RO': (McBlock.parseMcGeneric, True, True, True, ),
3291 'IEM_MC_MEM_MAP_U8_WO': (McBlock.parseMcGeneric, True, True, True, ),
3292 'IEM_MC_MEM_MAP_U16_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3293 'IEM_MC_MEM_MAP_U16_RW': (McBlock.parseMcGeneric, True, True, True, ),
3294 'IEM_MC_MEM_MAP_U16_RO': (McBlock.parseMcGeneric, True, True, True, ),
3295 'IEM_MC_MEM_MAP_U16_WO': (McBlock.parseMcGeneric, True, True, True, ),
3296 'IEM_MC_MEM_MAP_U32_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3297 'IEM_MC_MEM_MAP_U32_RW': (McBlock.parseMcGeneric, True, True, True, ),
3298 'IEM_MC_MEM_MAP_U32_RO': (McBlock.parseMcGeneric, True, True, True, ),
3299 'IEM_MC_MEM_MAP_U32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3300 'IEM_MC_MEM_MAP_U64_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3301 'IEM_MC_MEM_MAP_U64_RW': (McBlock.parseMcGeneric, True, True, True, ),
3302 'IEM_MC_MEM_MAP_U64_RO': (McBlock.parseMcGeneric, True, True, True, ),
3303 'IEM_MC_MEM_MAP_U64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3304 'IEM_MC_MEM_MAP_U128_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3305 'IEM_MC_MEM_MAP_U128_RW': (McBlock.parseMcGeneric, True, True, True, ),
3306 'IEM_MC_MEM_MAP_U128_RO': (McBlock.parseMcGeneric, True, True, True, ),
3307 'IEM_MC_MEM_MAP_U128_WO': (McBlock.parseMcGeneric, True, True, True, ),
3308 'IEM_MC_MEM_ROLLBACK_AND_UNMAP_WO': (McBlock.parseMcGeneric, True, True, True, ),
3309 'IEM_MC_MERGE_YREG_U32_U96_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3310 'IEM_MC_MERGE_YREG_U64_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3311 'IEM_MC_MERGE_YREG_U64HI_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3312 'IEM_MC_MERGE_YREG_U64LO_U64LO_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3313 'IEM_MC_MERGE_YREG_U64LO_U64LOCAL_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3314 'IEM_MC_MERGE_YREG_U64LOCAL_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3315 'IEM_MC_MODIFIED_MREG': (McBlock.parseMcGeneric, True, True, False, ),
3316 'IEM_MC_MODIFIED_MREG_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3317 'IEM_MC_NATIVE_EMIT_0': (McBlock.parseMcGeneric, True, True, True, ),
3318 'IEM_MC_NATIVE_EMIT_1': (McBlock.parseMcGeneric, True, True, True, ),
3319 'IEM_MC_NATIVE_EMIT_2': (McBlock.parseMcGeneric, True, True, True, ),
3320 'IEM_MC_NATIVE_EMIT_2_EX': (McBlock.parseMcGeneric, True, True, True, ),
3321 'IEM_MC_NATIVE_EMIT_3': (McBlock.parseMcGeneric, True, True, True, ),
3322 'IEM_MC_NATIVE_EMIT_4': (McBlock.parseMcGeneric, True, True, True, ),
3323 'IEM_MC_NATIVE_EMIT_5': (McBlock.parseMcGeneric, True, True, True, ),
3324 'IEM_MC_NATIVE_EMIT_6': (McBlock.parseMcGeneric, True, True, True, ),
3325 'IEM_MC_NATIVE_EMIT_7': (McBlock.parseMcGeneric, True, True, True, ),
3326 'IEM_MC_NATIVE_IF': (McBlock.parseMcNativeIf, False, False, True, ),
3327 'IEM_MC_NATIVE_ELSE': (McBlock.parseMcGenericCond, False, False, True, ),
3328 'IEM_MC_NATIVE_ENDIF': (McBlock.parseMcGenericCond, False, False, True, ),
3329 'IEM_MC_NATIVE_SET_AMD64_HOST_REG_FOR_LOCAL': (McBlock.parseMcGeneric, False, False, True, ),
3330 'IEM_MC_OR_2LOCS_U32': (McBlock.parseMcGeneric, False, False, False, ),
3331 'IEM_MC_OR_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3332 'IEM_MC_OR_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3333 'IEM_MC_OR_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3334 'IEM_MC_OR_GREG_U8': (McBlock.parseMcGeneric, True, True, True, ),
3335 'IEM_MC_OR_LOCAL_U16': (McBlock.parseMcGeneric, False, False, True, ),
3336 'IEM_MC_OR_LOCAL_U32': (McBlock.parseMcGeneric, False, False, True, ),
3337 'IEM_MC_OR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, True, ),
3338 'IEM_MC_POP_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3339 'IEM_MC_POP_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3340 'IEM_MC_POP_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3341 'IEM_MC_PREPARE_AVX_USAGE': (McBlock.parseMcGeneric, False, False, True),
3342 'IEM_MC_PREPARE_FPU_USAGE': (McBlock.parseMcGeneric, False, False, True),
3343 'IEM_MC_PREPARE_SSE_USAGE': (McBlock.parseMcGeneric, False, False, True),
3344 'IEM_MC_PUSH_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3345 'IEM_MC_PUSH_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3346 'IEM_MC_PUSH_FPU_RESULT_TWO': (McBlock.parseMcGeneric, True, True, False, ),
3347 'IEM_MC_PUSH_U16': (McBlock.parseMcGeneric, True, True, True, ),
3348 'IEM_MC_PUSH_U32': (McBlock.parseMcGeneric, True, True, True, ),
3349 'IEM_MC_PUSH_U32_SREG': (McBlock.parseMcGeneric, True, True, True, ),
3350 'IEM_MC_PUSH_U64': (McBlock.parseMcGeneric, True, True, True, ),
3351 'IEM_MC_RAISE_DIVIDE_ERROR_IF_LOCAL_IS_ZERO': (McBlock.parseMcGeneric, True, True, True, ),
3352 'IEM_MC_RAISE_GP0_IF_CPL_NOT_ZERO': (McBlock.parseMcGeneric, True, True, False, ),
3353 'IEM_MC_RAISE_GP0_IF_EFF_ADDR_UNALIGNED': (McBlock.parseMcGeneric, True, True, True, ),
3354 'IEM_MC_REF_EFLAGS': (McBlock.parseMcGeneric, False, False, True, ),
3355 'IEM_MC_REF_FPUREG': (McBlock.parseMcGeneric, False, False, False, ),
3356 'IEM_MC_REF_GREG_I32': (McBlock.parseMcGeneric, False, False, True, ),
3357 'IEM_MC_REF_GREG_I32_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3358 'IEM_MC_REF_GREG_I64': (McBlock.parseMcGeneric, False, False, True, ),
3359 'IEM_MC_REF_GREG_I64_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3360 'IEM_MC_REF_GREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
3361 'IEM_MC_REF_GREG_U16_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3362 'IEM_MC_REF_GREG_U32': (McBlock.parseMcGeneric, False, False, True, ),
3363 'IEM_MC_REF_GREG_U32_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3364 'IEM_MC_REF_GREG_U64': (McBlock.parseMcGeneric, False, False, True, ),
3365 'IEM_MC_REF_GREG_U64_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3366 'IEM_MC_REF_GREG_U8': (McBlock.parseMcGeneric, False, False, False, ), # threaded
3367 'IEM_MC_REF_GREG_U8_CONST': (McBlock.parseMcGeneric, False, False, False, ), # threaded
3368 'IEM_MC_REF_MREG_U32_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3369 'IEM_MC_REF_MREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
3370 'IEM_MC_REF_MREG_U64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3371 'IEM_MC_REF_XREG_R32_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3372 'IEM_MC_REF_XREG_R64_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3373 'IEM_MC_REF_XREG_U128': (McBlock.parseMcGeneric, False, False, True, ),
3374 'IEM_MC_REF_XREG_XMM': (McBlock.parseMcGeneric, False, False, True, ),
3375 'IEM_MC_REF_XREG_U128_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3376 'IEM_MC_REF_XREG_U32_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3377 'IEM_MC_REF_XREG_U64_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3378 'IEM_MC_REF_XREG_XMM_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3379 'IEM_MC_REF_YREG_U128': (McBlock.parseMcGeneric, False, False, False, ),
3380 'IEM_MC_REF_YREG_U128_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3381 'IEM_MC_REF_YREG_U64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3382 'IEM_MC_REL_CALL_S16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3383 'IEM_MC_REL_CALL_S32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3384 'IEM_MC_REL_CALL_S64_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3385 'IEM_MC_REL_JMP_S16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3386 'IEM_MC_REL_JMP_S32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3387 'IEM_MC_REL_JMP_S8_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3388 'IEM_MC_RETN_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3389 'IEM_MC_RETURN_ON_FAILURE': (McBlock.parseMcGeneric, False, False, False, ),
3390 'IEM_MC_SAR_LOCAL_S16': (McBlock.parseMcGeneric, False, False, True, ),
3391 'IEM_MC_SAR_LOCAL_S32': (McBlock.parseMcGeneric, False, False, True, ),
3392 'IEM_MC_SAR_LOCAL_S64': (McBlock.parseMcGeneric, False, False, True, ),
3393 'IEM_MC_SET_EFL_BIT': (McBlock.parseMcGeneric, True, True, True, ),
3394 'IEM_MC_SET_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3395 'IEM_MC_SET_RIP_U16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3396 'IEM_MC_SET_RIP_U32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3397 'IEM_MC_SET_RIP_U64_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3398 'IEM_MC_SHL_LOCAL_S16': (McBlock.parseMcGeneric, False, False, True, ),
3399 'IEM_MC_SHL_LOCAL_S32': (McBlock.parseMcGeneric, False, False, True, ),
3400 'IEM_MC_SHL_LOCAL_S64': (McBlock.parseMcGeneric, False, False, True, ),
3401 'IEM_MC_SHR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, False, ),
3402 'IEM_MC_STORE_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3403 'IEM_MC_STORE_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3404 'IEM_MC_STORE_FPU_RESULT_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3405 'IEM_MC_STORE_FPU_RESULT_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3406 'IEM_MC_STORE_FPUREG_R80_SRC_REF': (McBlock.parseMcGeneric, True, True, False, ),
3407 'IEM_MC_STORE_GREG_I32': (McBlock.parseMcGeneric, True, True, True, ),
3408 'IEM_MC_STORE_GREG_I64': (McBlock.parseMcGeneric, True, True, True, ),
3409 'IEM_MC_STORE_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3410 'IEM_MC_STORE_GREG_U16_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3411 'IEM_MC_STORE_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3412 'IEM_MC_STORE_GREG_U32_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3413 'IEM_MC_STORE_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3414 'IEM_MC_STORE_GREG_U64_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3415 'IEM_MC_STORE_GREG_U8': (McBlock.parseMcGeneric, True, True, True, ), # thrd var
3416 'IEM_MC_STORE_GREG_U8_CONST': (McBlock.parseMcGeneric, True, True, True, ), # thrd var
3417 'IEM_MC_STORE_GREG_PAIR_U32': (McBlock.parseMcGeneric, True, True, False, ),
3418 'IEM_MC_STORE_GREG_PAIR_U64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3419 'IEM_MC_STORE_MEM_I16_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3420 'IEM_MC_STORE_MEM_I32_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3421 'IEM_MC_STORE_MEM_I64_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3422 'IEM_MC_STORE_MEM_I8_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3423 'IEM_MC_STORE_MEM_INDEF_D80_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3424 'IEM_MC_STORE_MEM_NEG_QNAN_R32_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3425 'IEM_MC_STORE_MEM_NEG_QNAN_R64_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3426 'IEM_MC_STORE_MEM_NEG_QNAN_R80_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3427 'IEM_MC_STORE_MEM_U128': (McBlock.parseMcGeneric, True, True, False, ),
3428 'IEM_MC_STORE_MEM_U128_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3429 'IEM_MC_STORE_MEM_U128_ALIGN_SSE': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3430 'IEM_MC_STORE_MEM_U16': (McBlock.parseMcGeneric, True, True, True, ),
3431 'IEM_MC_STORE_MEM_U16_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3432 'IEM_MC_STORE_MEM_U256': (McBlock.parseMcGeneric, True, True, False, ),
3433 'IEM_MC_STORE_MEM_U256_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3434 'IEM_MC_STORE_MEM_U256_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3435 'IEM_MC_STORE_MEM_U32': (McBlock.parseMcGeneric, True, True, True, ),
3436 'IEM_MC_STORE_MEM_U32_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3437 'IEM_MC_STORE_MEM_U64': (McBlock.parseMcGeneric, True, True, True, ),
3438 'IEM_MC_STORE_MEM_U64_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3439 'IEM_MC_STORE_MEM_U8': (McBlock.parseMcGeneric, True, True, True, ),
3440 'IEM_MC_STORE_MEM_U8_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3441 'IEM_MC_STORE_MREG_U8': (McBlock.parseMcGeneric, True, True, False, ),
3442 'IEM_MC_STORE_MREG_U16': (McBlock.parseMcGeneric, True, True, False, ),
3443 'IEM_MC_STORE_MREG_U32': (McBlock.parseMcGeneric, True, True, False, ),
3444 'IEM_MC_STORE_MREG_U32_ZX_U64': (McBlock.parseMcGeneric, True, True, False, ),
3445 'IEM_MC_STORE_MREG_U64': (McBlock.parseMcGeneric, True, True, False, ),
3446 'IEM_MC_STORE_SREG_BASE_U32': (McBlock.parseMcGeneric, True, True, False, ),
3447 'IEM_MC_STORE_SREG_BASE_U64': (McBlock.parseMcGeneric, True, True, False, ),
3448 'IEM_MC_STORE_XREG_R32': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3449 'IEM_MC_STORE_XREG_R64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3450 'IEM_MC_STORE_XREG_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3451 'IEM_MC_STORE_XREG_U16': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3452 'IEM_MC_STORE_XREG_U32': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3453 'IEM_MC_STORE_XREG_U32_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3454 'IEM_MC_STORE_XREG_U32_ZX_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3455 'IEM_MC_STORE_XREG_U64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3456 'IEM_MC_STORE_XREG_U64_ZX_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3457 'IEM_MC_STORE_XREG_U8': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3458 'IEM_MC_STORE_XREG_XMM': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3459 'IEM_MC_STORE_XREG_XMM_U32': (McBlock.parseMcGeneric, True, True, False, ),
3460 'IEM_MC_STORE_XREG_XMM_U64': (McBlock.parseMcGeneric, True, True, False, ),
3461 'IEM_MC_STORE_YREG_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3462 'IEM_MC_STORE_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3463 'IEM_MC_STORE_YREG_U256_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3464 'IEM_MC_STORE_YREG_YMM_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3465 'IEM_MC_STORE_YREG_U32_U256': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3466 'IEM_MC_STORE_YREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3467 'IEM_MC_STORE_YREG_U64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3468 'IEM_MC_STORE_YREG_U64_U256': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3469 'IEM_MC_STORE_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3470 'IEM_MC_SUB_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3471 'IEM_MC_SUB_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3472 'IEM_MC_SUB_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3473 'IEM_MC_SUB_LOCAL_U16': (McBlock.parseMcGeneric, False, False, False, ),
3474 'IEM_MC_UPDATE_FPU_OPCODE_IP': (McBlock.parseMcGeneric, True, True, False, ),
3475 'IEM_MC_UPDATE_FSW': (McBlock.parseMcGeneric, True, True, False, ),
3476 'IEM_MC_UPDATE_FSW_CONST': (McBlock.parseMcGeneric, True, True, False, ),
3477 'IEM_MC_UPDATE_FSW_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3478 'IEM_MC_UPDATE_FSW_THEN_POP_POP': (McBlock.parseMcGeneric, True, True, False, ),
3479 'IEM_MC_UPDATE_FSW_WITH_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3480 'IEM_MC_UPDATE_FSW_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3481 'IEM_MC_NO_NATIVE_RECOMPILE': (McBlock.parseMcGeneric, False, False, False, ),
3482};
3483# pylint: enable=line-too-long
3484
3485## List of microcode blocks.
3486g_aoMcBlocks = [] # type: List[McBlock]
3487
3488
3489
3490class ParserException(Exception):
3491 """ Parser exception """
3492 def __init__(self, sMessage):
3493 Exception.__init__(self, sMessage);
3494
3495
3496class SimpleParser(object): # pylint: disable=too-many-instance-attributes
3497 """
3498 Parser of IEMAllInstruction*.cpp.h instruction specifications.
3499 """
3500
3501 ## @name Parser state.
3502 ## @{
3503 kiCode = 0;
3504 kiCommentMulti = 1;
3505 ## @}
3506
3507 class Macro(object):
3508 """ Macro """
3509 def __init__(self, sName, asArgs, sBody, iLine):
3510 self.sName = sName; ##< The macro name.
3511 self.asArgs = asArgs; ##< None if simple macro, list of parameters otherwise.
3512 self.sBody = sBody;
3513 self.iLine = iLine;
3514 self.oReArgMatch = re.compile(r'(\s*##\s*|\b)(' + '|'.join(asArgs) + r')(\s*##\s*|\b)') if asArgs else None;
3515
3516 @staticmethod
3517 def _needSpace(ch):
3518 """ This is just to make the expanded output a bit prettier. """
3519 return ch.isspace() and ch != '(';
3520
3521 def expandMacro(self, oParent, asArgs = None):
3522 """ Expands the macro body with the given arguments. """
3523 _ = oParent;
3524 sBody = self.sBody;
3525
3526 if self.oReArgMatch:
3527 assert len(asArgs) == len(self.asArgs);
3528 #oParent.debug('%s: %s' % (self.sName, self.oReArgMatch.pattern,));
3529
3530 dArgs = { self.asArgs[iArg]: sValue for iArg, sValue in enumerate(asArgs) };
3531 oMatch = self.oReArgMatch.search(sBody);
3532 while oMatch:
3533 sName = oMatch.group(2);
3534 #oParent.debug('%s %s..%s (%s)' % (sName, oMatch.start(), oMatch.end(),oMatch.group()));
3535 sValue = dArgs[sName];
3536 sPre = '';
3537 if not oMatch.group(1) and oMatch.start() > 0 and self._needSpace(sBody[oMatch.start()]):
3538 sPre = ' ';
3539 sPost = '';
3540 if not oMatch.group(3) and oMatch.end() < len(sBody) and self._needSpace(sBody[oMatch.end()]):
3541 sPost = ' ';
3542 sBody = sBody[ : oMatch.start()] + sPre + sValue + sPost + sBody[oMatch.end() : ];
3543 oMatch = self.oReArgMatch.search(sBody, oMatch.start() + len(sValue));
3544 else:
3545 assert not asArgs;
3546
3547 return sBody;
3548
3549 class PreprocessorConditional(object):
3550 """ Preprocessor conditional (#if/#ifdef/#ifndef/#elif/#else/#endif). """
3551
3552 ## Known defines.
3553 # - A value of 1 indicates that it's always defined.
3554 # - A value of 0 if it's always undefined
3555 # - A value of -1 if it's an arch and it depends of script parameters.
3556 # - A value of -2 if it's not recognized when filtering MC blocks.
3557 kdKnownDefines = {
3558 'IEM_WITH_ONE_BYTE_TABLE': 1,
3559 'IEM_WITH_TWO_BYTE_TABLE': 1,
3560 'IEM_WITH_THREE_0F_38': 1,
3561 'IEM_WITH_THREE_0F_3A': 1,
3562 'IEM_WITH_THREE_BYTE_TABLES': 1,
3563 'IEM_WITH_3DNOW': 1,
3564 'IEM_WITH_3DNOW_TABLE': 1,
3565 'IEM_WITH_VEX': 1,
3566 'IEM_WITH_VEX_TABLES': 1,
3567 'VBOX_WITH_NESTED_HWVIRT_VMX': 1,
3568 'VBOX_WITH_NESTED_HWVIRT_VMX_EPT': 1,
3569 'VBOX_WITH_NESTED_HWVIRT_SVM': 1,
3570 'LOG_ENABLED': 1,
3571 'RT_WITHOUT_PRAGMA_ONCE': 0,
3572 'TST_IEM_CHECK_MC': 0,
3573 'IEM_WITHOUT_ASSEMBLY': -2, ##< @todo ??
3574 'RT_ARCH_AMD64': -1,
3575 'RT_ARCH_ARM64': -1,
3576 'RT_ARCH_ARM32': -1,
3577 'RT_ARCH_X86': -1,
3578 'RT_ARCH_SPARC': -1,
3579 'RT_ARCH_SPARC64': -1,
3580 };
3581 kdBuildArchToIprt = {
3582 'amd64': 'RT_ARCH_AMD64',
3583 'arm64': 'RT_ARCH_ARM64',
3584 'sparc32': 'RT_ARCH_SPARC64',
3585 };
3586 ## For parsing the next defined(xxxx).
3587 koMatchDefined = re.compile(r'\s*defined\s*\(\s*([^ \t)]+)\s*\)\s*');
3588
3589 def __init__(self, sType, sExpr):
3590 self.sType = sType;
3591 self.sExpr = sExpr; ##< Expression without command and no leading or trailing spaces.
3592 self.aoElif = [] # type: List[PreprocessorConditional]
3593 self.fInElse = [];
3594 if sType in ('if', 'elif'):
3595 self.checkExpression(sExpr);
3596 else:
3597 self.checkSupportedDefine(sExpr)
3598
3599 @staticmethod
3600 def checkSupportedDefine(sDefine):
3601 """ Checks that sDefine is one that we support. Raises exception if unuspported. """
3602 #print('debug: checkSupportedDefine: %s' % (sDefine,), file = sys.stderr);
3603 if sDefine in SimpleParser.PreprocessorConditional.kdKnownDefines:
3604 return True;
3605 if sDefine.startswith('VMM_INCLUDED_') and sDefine.endswith('_h'):
3606 return True;
3607 raise Exception('Unsupported define: %s' % (sDefine,));
3608
3609 @staticmethod
3610 def checkExpression(sExpr):
3611 """ Check that the expression is supported. Raises exception if not. """
3612 #print('debug: checkExpression: %s' % (sExpr,), file = sys.stderr);
3613 if sExpr in ('0', '1'):
3614 return True;
3615
3616 off = 0;
3617 cParan = 0;
3618 while off < len(sExpr):
3619 ch = sExpr[off];
3620
3621 # Unary operator or parentheses:
3622 if ch in ('(', '!'):
3623 if ch == '(':
3624 cParan += 1;
3625 off += 1;
3626 else:
3627 # defined(xxxx)
3628 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3629 if oMatch:
3630 SimpleParser.PreprocessorConditional.checkSupportedDefine(oMatch.group(1));
3631 elif sExpr[off:] != '1':
3632 raise Exception('Cannot grok: \'%s\' (at %u in: \'%s\')' % (sExpr[off:10], off + 1, sExpr,));
3633 off = oMatch.end();
3634
3635 # Look for closing parentheses.
3636 while off < len(sExpr) and sExpr[off].isspace():
3637 off += 1;
3638 if cParan > 0:
3639 while off < len(sExpr) and sExpr[off] == ')':
3640 if cParan <= 0:
3641 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3642 cParan -= 1;
3643 off += 1;
3644 while off < len(sExpr) and sExpr[off].isspace():
3645 off += 1;
3646
3647 # Look for binary operator.
3648 if off >= len(sExpr):
3649 break;
3650 if sExpr[off:off + 2] in ('||', '&&'):
3651 off += 2;
3652 else:
3653 raise Exception('Cannot grok operator: \'%s\' (at %u in: \'%s\')' % (sExpr[off:2], off + 1, sExpr,));
3654
3655 # Skip spaces.
3656 while off < len(sExpr) and sExpr[off].isspace():
3657 off += 1;
3658 if cParan != 0:
3659 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3660 return True;
3661
3662 @staticmethod
3663 def isArchIncludedInExpr(sExpr, sArch):
3664 """ Checks if sArch is included in the given expression. """
3665 # We only grok defined() [|| defined()...] and [1|0] at the moment.
3666 if sExpr == '0':
3667 return False;
3668 if sExpr == '1':
3669 return True;
3670 off = 0;
3671 while off < len(sExpr):
3672 # defined(xxxx)
3673 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3674 if not oMatch:
3675 if sExpr[off:] == '1':
3676 return True;
3677 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3678 if SimpleParser.PreprocessorConditional.matchDefined(oMatch.group(1), sArch):
3679 return True;
3680 off = oMatch.end();
3681
3682 # Look for OR operator.
3683 while off + 1 < len(sExpr) and sExpr[off + 1].isspace():
3684 off += 1;
3685 if off >= len(sExpr):
3686 break;
3687 if sExpr.startswith('||'):
3688 off += 2;
3689 else:
3690 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3691
3692 return False;
3693
3694 @staticmethod
3695 def matchArch(sDefine, sArch):
3696 """ Compares sDefine (RT_ARCH_XXXX) and sArch (x86, amd64, arm64, ++). """
3697 return SimpleParser.PreprocessorConditional.kdBuildArchToIprt[sArch] == sDefine;
3698
3699 @staticmethod
3700 def matchDefined(sExpr, sArch):
3701 """ Check the result of an ifdef/ifndef expression, given sArch. """
3702 iDefine = SimpleParser.PreprocessorConditional.kdKnownDefines.get(sExpr, 0);
3703 if iDefine == -2:
3704 raise Exception('Unsupported define for MC block filtering: %s' % (sExpr,));
3705 return iDefine == 1 or (iDefine == -1 and SimpleParser.PreprocessorConditional.matchArch(sExpr, sArch));
3706
3707 def isArchIncludedInPrimaryBlock(self, sArch):
3708 """ Checks if sArch is included in the (primary) 'if' block. """
3709 if self.sType == 'ifdef':
3710 return self.matchDefined(self.sExpr, sArch);
3711 if self.sType == 'ifndef':
3712 return not self.matchDefined(self.sExpr, sArch);
3713 return self.isArchIncludedInExpr(self.sExpr, sArch);
3714
3715 @staticmethod
3716 def isInBlockForArch(aoCppCondStack, sArch, iLine):
3717 """ Checks if sArch is included in the current conditional block. """
3718 _ = iLine;
3719 #print('debug: isInBlockForArch(%s,%s); line %s' % (len(aoCppCondStack), sArch, iLine), file = sys.stderr);
3720 for oCond in aoCppCondStack:
3721 if oCond.isArchIncludedInPrimaryBlock(sArch):
3722 if oCond.aoElif or oCond.fInElse:
3723 #print('debug: isInBlockForArch -> False #1', file = sys.stderr);
3724 return False;
3725 #print('debug: isInBlockForArch(%s,%s): in IF-block' % (len(aoCppCondStack), sArch), file = sys.stderr);
3726 else:
3727 fFine = False;
3728 for oElifCond in oCond.aoElif:
3729 if oElifCond.isArchIncludedInPrimaryBlock(sArch):
3730 if oElifCond is not oCond.aoElif[-1] or oCond.fInElse:
3731 #print('debug: isInBlockForArch -> False #3', file = sys.stderr);
3732 return False;
3733 fFine = True;
3734 if not fFine and not oCond.fInElse:
3735 #print('debug: isInBlockForArch -> False #4', file = sys.stderr);
3736 return False;
3737 #print('debug: isInBlockForArch -> True', file = sys.stderr);
3738 return True;
3739
3740 def __init__(self, sSrcFile, asLines, sDefaultMap, sHostArch, oInheritMacrosFrom = None):
3741 self.sSrcFile = sSrcFile;
3742 self.asLines = asLines;
3743 self.iLine = 0;
3744 self.iState = self.kiCode;
3745 self.sComment = '';
3746 self.iCommentLine = 0;
3747 self.aoCurInstrs = [] # type: List[Instruction]
3748 self.oCurFunction = None # type: DecoderFunction
3749 self.iMcBlockInFunc = 0;
3750 self.oCurMcBlock = None # type: McBlock
3751 self.dMacros = {} # type: Dict[str, SimpleParser.Macro]
3752 self.oReMacros = None # type: re ##< Regular expression matching invocations of anything in self.dMacros.
3753 if oInheritMacrosFrom:
3754 self.dMacros = dict(oInheritMacrosFrom.dMacros);
3755 self.oReMacros = oInheritMacrosFrom.oReMacros;
3756 self.aoCppCondStack = [] # type: List[PreprocessorConditional] ##< Preprocessor conditional stack.
3757 self.sHostArch = sHostArch;
3758
3759 assert sDefaultMap in g_dInstructionMaps;
3760 self.oDefaultMap = g_dInstructionMaps[sDefaultMap];
3761
3762 self.cTotalInstr = 0;
3763 self.cTotalStubs = 0;
3764 self.cTotalTagged = 0;
3765 self.cTotalMcBlocks = 0;
3766
3767 self.oReMacroName = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3768 self.oReMnemonic = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3769 self.oReStatsName = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3770 self.oReFunctionName= re.compile(r'^iemOp_[A-Za-z_][A-Za-z0-9_]*$');
3771 self.oReGroupName = re.compile(r'^og_[a-z0-9]+(|_[a-z0-9]+|_[a-z0-9]+_[a-z0-9]+)$');
3772 self.oReDisEnum = re.compile(r'^OP_[A-Z0-9_]+$');
3773 self.oReFunTable = re.compile(r'^(IEM_STATIC|static) +const +PFNIEMOP +g_apfn[A-Za-z0-9_]+ *\[ *\d* *\] *= *$');
3774 self.oReComment = re.compile(r'//.*?$|/\*.*?\*/'); ## Full comments.
3775 self.oReHashDefine2 = re.compile(r'(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)\(([^)]*)\)\s*(.*)\Z'); ##< With arguments.
3776 self.oReHashDefine3 = re.compile(r'(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)[^(]\s*(.*)\Z'); ##< Simple, no arguments.
3777 self.oReMcBeginEnd = re.compile(r'\bIEM_MC_(BEGIN|END|DEFER_TO_CIMPL_[1-5]_RET)\s*\('); ##> Not DEFER_TO_CIMPL_0_RET!
3778 self.fDebug = True;
3779 self.fDebugMc = False;
3780 self.fDebugPreproc = False;
3781
3782 self.dTagHandlers = {
3783 '@opbrief': self.parseTagOpBrief,
3784 '@opdesc': self.parseTagOpDesc,
3785 '@opmnemonic': self.parseTagOpMnemonic,
3786 '@op1': self.parseTagOpOperandN,
3787 '@op2': self.parseTagOpOperandN,
3788 '@op3': self.parseTagOpOperandN,
3789 '@op4': self.parseTagOpOperandN,
3790 '@oppfx': self.parseTagOpPfx,
3791 '@opmaps': self.parseTagOpMaps,
3792 '@opcode': self.parseTagOpcode,
3793 '@opcodesub': self.parseTagOpcodeSub,
3794 '@openc': self.parseTagOpEnc,
3795 #@opfltest: Lists all flags that will be used as input in some way.
3796 '@opfltest': self.parseTagOpEFlags,
3797 #@opflmodify: Lists all EFLAGS modified. Includes @opflset, @opflcleared and @opflundef (if applicable).
3798 '@opflmodify': self.parseTagOpEFlags,
3799 #@opflclear: Lists all flags that will be set (set to 1).
3800 '@opflset': self.parseTagOpEFlags,
3801 #@opflclear: Lists all flags that will be cleared (set to 0).
3802 '@opflclear': self.parseTagOpEFlags,
3803 #@opflundef: List of flag documented as undefined.
3804 '@opflundef': self.parseTagOpEFlags,
3805 #@opflclass: Shorthand for defining flag behaviour (@opfltest, @opfmodify, @opflset, @opflclear, @opflundef).
3806 '@opflclass': self.parseTagOpEFlagsClass,
3807 '@ophints': self.parseTagOpHints,
3808 '@opdisenum': self.parseTagOpDisEnum,
3809 '@opmincpu': self.parseTagOpMinCpu,
3810 '@opcpuid': self.parseTagOpCpuId,
3811 '@opgroup': self.parseTagOpGroup,
3812 '@opunused': self.parseTagOpUnusedInvalid,
3813 '@opinvalid': self.parseTagOpUnusedInvalid,
3814 '@opinvlstyle': self.parseTagOpUnusedInvalid,
3815 '@optest': self.parseTagOpTest,
3816 '@optestign': self.parseTagOpTestIgnore,
3817 '@optestignore': self.parseTagOpTestIgnore,
3818 '@opcopytests': self.parseTagOpCopyTests,
3819 '@oponly': self.parseTagOpOnlyTest,
3820 '@oponlytest': self.parseTagOpOnlyTest,
3821 '@opxcpttype': self.parseTagOpXcptType,
3822 '@opstats': self.parseTagOpStats,
3823 '@opfunction': self.parseTagOpFunction,
3824 '@opdone': self.parseTagOpDone,
3825 };
3826 for i in range(48):
3827 self.dTagHandlers['@optest%u' % (i,)] = self.parseTagOpTestNum;
3828 self.dTagHandlers['@optest[%u]' % (i,)] = self.parseTagOpTestNum;
3829
3830 self.asErrors = [];
3831
3832 def raiseError(self, sMessage):
3833 """
3834 Raise error prefixed with the source and line number.
3835 """
3836 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iLine, sMessage,));
3837
3838 def raiseCommentError(self, iLineInComment, sMessage):
3839 """
3840 Similar to raiseError, but the line number is iLineInComment + self.iCommentLine.
3841 """
3842 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3843
3844 def error(self, sMessage):
3845 """
3846 Adds an error.
3847 returns False;
3848 """
3849 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iLine, sMessage,));
3850 return False;
3851
3852 def errorOnLine(self, iLine, sMessage):
3853 """
3854 Adds an error.
3855 returns False;
3856 """
3857 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, iLine, sMessage,));
3858 return False;
3859
3860 def errorComment(self, iLineInComment, sMessage):
3861 """
3862 Adds a comment error.
3863 returns False;
3864 """
3865 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3866 return False;
3867
3868 def printErrors(self):
3869 """
3870 Print the errors to stderr.
3871 Returns number of errors.
3872 """
3873 if self.asErrors:
3874 sys.stderr.write(u''.join(self.asErrors));
3875 return len(self.asErrors);
3876
3877 def debug(self, sMessage):
3878 """
3879 For debugging.
3880 """
3881 if self.fDebug:
3882 print('debug: %s' % (sMessage,), file = sys.stderr);
3883
3884 def stripComments(self, sLine):
3885 """
3886 Returns sLine with comments stripped.
3887
3888 Complains if traces of incomplete multi-line comments are encountered.
3889 """
3890 sLine = self.oReComment.sub(" ", sLine);
3891 if sLine.find('/*') >= 0 or sLine.find('*/') >= 0:
3892 self.error('Unexpected multi-line comment will not be handled correctly. Please simplify.');
3893 return sLine;
3894
3895 def parseFunctionTable(self, sLine):
3896 """
3897 Parses a PFNIEMOP table, updating/checking the @oppfx value.
3898
3899 Note! Updates iLine as it consumes the whole table.
3900 """
3901
3902 #
3903 # Extract the table name.
3904 #
3905 sName = re.search(r' *([a-zA-Z_0-9]+) *\[', sLine).group(1);
3906 oMap = g_dInstructionMapsByIemName.get(sName);
3907 if not oMap:
3908 self.debug('No map for PFNIEMOP table: %s' % (sName,));
3909 oMap = self.oDefaultMap; # This is wrong wrong wrong.
3910
3911 #
3912 # All but the g_apfnOneByteMap & g_apfnEscF1_E0toFF tables uses four
3913 # entries per byte:
3914 # no prefix, 066h prefix, f3h prefix, f2h prefix
3915 # Those tables has 256 & 32 entries respectively.
3916 #
3917 cEntriesPerByte = 4;
3918 cValidTableLength = 1024;
3919 asPrefixes = ('none', '0x66', '0xf3', '0xf2');
3920
3921 oEntriesMatch = re.search(r'\[ *(256|32) *\]', sLine);
3922 if oEntriesMatch:
3923 cEntriesPerByte = 1;
3924 cValidTableLength = int(oEntriesMatch.group(1));
3925 asPrefixes = (None,);
3926
3927 #
3928 # The next line should be '{' and nothing else.
3929 #
3930 if self.iLine >= len(self.asLines) or not re.match('^ *{ *$', self.asLines[self.iLine]):
3931 return self.errorOnLine(self.iLine + 1, 'Expected lone "{" on line following PFNIEMOP table %s start' % (sName, ));
3932 self.iLine += 1;
3933
3934 #
3935 # Parse till we find the end of the table.
3936 #
3937 iEntry = 0;
3938 while self.iLine < len(self.asLines):
3939 # Get the next line and strip comments and spaces (assumes no
3940 # multi-line comments).
3941 sLine = self.asLines[self.iLine];
3942 self.iLine += 1;
3943 sLine = self.stripComments(sLine).strip();
3944
3945 # Split the line up into entries, expanding IEMOP_X4 usage.
3946 asEntries = sLine.split(',');
3947 for i in range(len(asEntries) - 1, -1, -1):
3948 sEntry = asEntries[i].strip();
3949 if sEntry.startswith('IEMOP_X4(') and sEntry[-1] == ')':
3950 sEntry = (sEntry[len('IEMOP_X4('):-1]).strip();
3951 asEntries.insert(i + 1, sEntry);
3952 asEntries.insert(i + 1, sEntry);
3953 asEntries.insert(i + 1, sEntry);
3954 if sEntry:
3955 asEntries[i] = sEntry;
3956 else:
3957 del asEntries[i];
3958
3959 # Process the entries.
3960 for sEntry in asEntries:
3961 if sEntry in ('};', '}'):
3962 if iEntry != cValidTableLength:
3963 return self.error('Wrong table length for %s: %#x, expected %#x' % (sName, iEntry, cValidTableLength, ));
3964 return True;
3965 if sEntry.startswith('iemOp_Invalid'):
3966 pass; # skip
3967 else:
3968 # Look up matching instruction by function.
3969 sPrefix = asPrefixes[iEntry % cEntriesPerByte];
3970 sOpcode = '%#04x' % (iEntry // cEntriesPerByte);
3971 aoInstr = g_dAllInstructionsByFunction.get(sEntry);
3972 if aoInstr:
3973 if not isinstance(aoInstr, list):
3974 aoInstr = [aoInstr,];
3975 oInstr = None;
3976 for oCurInstr in aoInstr:
3977 if oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix == sPrefix:
3978 pass;
3979 elif oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix is None:
3980 oCurInstr.sPrefix = sPrefix;
3981 elif oCurInstr.sOpcode is None and oCurInstr.sPrefix is None:
3982 oCurInstr.sOpcode = sOpcode;
3983 oCurInstr.sPrefix = sPrefix;
3984 else:
3985 continue;
3986 oInstr = oCurInstr;
3987 break;
3988 if not oInstr:
3989 oInstr = aoInstr[0].copy(oMap = oMap, sOpcode = sOpcode, sPrefix = sPrefix);
3990 aoInstr.append(oInstr);
3991 g_dAllInstructionsByFunction[sEntry] = aoInstr;
3992 g_aoAllInstructions.append(oInstr);
3993 oMap.aoInstructions.append(oInstr);
3994 else:
3995 self.debug('Function "%s", entry %#04x / byte %#04x in %s, is not associated with an instruction.'
3996 % (sEntry, iEntry, iEntry // cEntriesPerByte, sName,));
3997 iEntry += 1;
3998
3999 return self.error('Unexpected end of file in PFNIEMOP table');
4000
4001 def addInstruction(self, iLine = None):
4002 """
4003 Adds an instruction.
4004 """
4005 oInstr = Instruction(self.sSrcFile, self.iLine if iLine is None else iLine);
4006 g_aoAllInstructions.append(oInstr);
4007 self.aoCurInstrs.append(oInstr);
4008 return oInstr;
4009
4010 def deriveMnemonicAndOperandsFromStats(self, oInstr, sStats):
4011 """
4012 Derives the mnemonic and operands from a IEM stats base name like string.
4013 """
4014 if oInstr.sMnemonic is None:
4015 asWords = sStats.split('_');
4016 oInstr.sMnemonic = asWords[0].lower();
4017 if len(asWords) > 1 and not oInstr.aoOperands:
4018 for sType in asWords[1:]:
4019 if sType in g_kdOpTypes:
4020 oInstr.aoOperands.append(Operand(g_kdOpTypes[sType][1], sType));
4021 else:
4022 #return self.error('unknown operand type: %s (instruction: %s)' % (sType, oInstr))
4023 return False;
4024 return True;
4025
4026 def doneInstructionOne(self, oInstr, iLine):
4027 """
4028 Complete the parsing by processing, validating and expanding raw inputs.
4029 """
4030 assert oInstr.iLineCompleted is None;
4031 oInstr.iLineCompleted = iLine;
4032
4033 #
4034 # Specified instructions.
4035 #
4036 if oInstr.cOpTags > 0:
4037 if oInstr.sStats is None:
4038 pass;
4039
4040 #
4041 # Unspecified legacy stuff. We generally only got a few things to go on here.
4042 # /** Opcode 0x0f 0x00 /0. */
4043 # FNIEMOPRM_DEF(iemOp_Grp6_sldt)
4044 #
4045 else:
4046 #if oInstr.sRawOldOpcodes:
4047 #
4048 #if oInstr.sMnemonic:
4049 pass;
4050
4051 #
4052 # Common defaults.
4053 #
4054
4055 # Guess mnemonic and operands from stats if the former is missing.
4056 if oInstr.sMnemonic is None:
4057 if oInstr.sStats is not None:
4058 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sStats);
4059 elif oInstr.sFunction is not None:
4060 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sFunction.replace('iemOp_', ''));
4061
4062 # Derive the disassembler op enum constant from the mnemonic.
4063 if oInstr.sDisEnum is None and oInstr.sMnemonic is not None:
4064 oInstr.sDisEnum = 'OP_' + oInstr.sMnemonic.upper();
4065
4066 # Derive the IEM statistics base name from mnemonic and operand types.
4067 if oInstr.sStats is None:
4068 if oInstr.sFunction is not None:
4069 oInstr.sStats = oInstr.sFunction.replace('iemOp_', '');
4070 elif oInstr.sMnemonic is not None:
4071 oInstr.sStats = oInstr.sMnemonic;
4072 for oOperand in oInstr.aoOperands:
4073 if oOperand.sType:
4074 oInstr.sStats += '_' + oOperand.sType;
4075
4076 # Derive the IEM function name from mnemonic and operand types.
4077 if oInstr.sFunction is None:
4078 if oInstr.sMnemonic is not None:
4079 oInstr.sFunction = 'iemOp_' + oInstr.sMnemonic;
4080 for oOperand in oInstr.aoOperands:
4081 if oOperand.sType:
4082 oInstr.sFunction += '_' + oOperand.sType;
4083 elif oInstr.sStats:
4084 oInstr.sFunction = 'iemOp_' + oInstr.sStats;
4085
4086 #
4087 # Apply default map and then add the instruction to all it's groups.
4088 #
4089 if not oInstr.aoMaps:
4090 oInstr.aoMaps = [ self.oDefaultMap, ];
4091 for oMap in oInstr.aoMaps:
4092 oMap.aoInstructions.append(oInstr);
4093
4094 #
4095 # Derive encoding from operands and maps.
4096 #
4097 if oInstr.sEncoding is None:
4098 if not oInstr.aoOperands:
4099 if oInstr.fUnused and oInstr.sSubOpcode:
4100 oInstr.sEncoding = 'VEX.ModR/M' if oInstr.onlyInVexMaps() else 'ModR/M';
4101 else:
4102 oInstr.sEncoding = 'VEX.fixed' if oInstr.onlyInVexMaps() else 'fixed';
4103 elif oInstr.aoOperands[0].usesModRM():
4104 if (len(oInstr.aoOperands) >= 2 and oInstr.aoOperands[1].sWhere == 'vvvv') \
4105 or oInstr.onlyInVexMaps():
4106 oInstr.sEncoding = 'VEX.ModR/M';
4107 else:
4108 oInstr.sEncoding = 'ModR/M';
4109
4110 #
4111 # Check the opstat value and add it to the opstat indexed dictionary.
4112 #
4113 if oInstr.sStats:
4114 if oInstr.sStats not in g_dAllInstructionsByStat:
4115 g_dAllInstructionsByStat[oInstr.sStats] = oInstr;
4116 else:
4117 self.error('Duplicate opstat value "%s"\nnew: %s\nold: %s'
4118 % (oInstr.sStats, oInstr, g_dAllInstructionsByStat[oInstr.sStats],));
4119
4120 #
4121 # Add to function indexed dictionary. We allow multiple instructions per function.
4122 #
4123 if oInstr.sFunction:
4124 if oInstr.sFunction not in g_dAllInstructionsByFunction:
4125 g_dAllInstructionsByFunction[oInstr.sFunction] = [oInstr,];
4126 else:
4127 g_dAllInstructionsByFunction[oInstr.sFunction].append(oInstr);
4128
4129 #self.debug('%d..%d: %s; %d @op tags' % (oInstr.iLineCreated, oInstr.iLineCompleted, oInstr.sFunction, oInstr.cOpTags));
4130 return True;
4131
4132 def doneInstructions(self, iLineInComment = None, fEndOfFunction = False):
4133 """
4134 Done with current instruction.
4135 """
4136 for oInstr in self.aoCurInstrs:
4137 self.doneInstructionOne(oInstr, self.iLine if iLineInComment is None else self.iCommentLine + iLineInComment);
4138 if oInstr.fStub:
4139 self.cTotalStubs += 1;
4140
4141 self.cTotalInstr += len(self.aoCurInstrs);
4142
4143 self.sComment = '';
4144 self.aoCurInstrs = [];
4145 if fEndOfFunction:
4146 #self.debug('%s: oCurFunction=None' % (self.iLine, ));
4147 if self.oCurFunction:
4148 self.oCurFunction.complete(self.iLine, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine]);
4149 self.oCurFunction = None;
4150 self.iMcBlockInFunc = 0;
4151 return True;
4152
4153 def setInstrunctionAttrib(self, sAttrib, oValue, fOverwrite = False):
4154 """
4155 Sets the sAttrib of all current instruction to oValue. If fOverwrite
4156 is False, only None values and empty strings are replaced.
4157 """
4158 for oInstr in self.aoCurInstrs:
4159 if fOverwrite is not True:
4160 oOldValue = getattr(oInstr, sAttrib);
4161 if oOldValue is not None:
4162 continue;
4163 setattr(oInstr, sAttrib, oValue);
4164
4165 def setInstrunctionArrayAttrib(self, sAttrib, iEntry, oValue, fOverwrite = False):
4166 """
4167 Sets the iEntry of the array sAttrib of all current instruction to oValue.
4168 If fOverwrite is False, only None values and empty strings are replaced.
4169 """
4170 for oInstr in self.aoCurInstrs:
4171 aoArray = getattr(oInstr, sAttrib);
4172 while len(aoArray) <= iEntry:
4173 aoArray.append(None);
4174 if fOverwrite is True or aoArray[iEntry] is None:
4175 aoArray[iEntry] = oValue;
4176
4177 def parseCommentOldOpcode(self, asLines):
4178 """ Deals with 'Opcode 0xff /4' like comments """
4179 asWords = asLines[0].split();
4180 if len(asWords) >= 2 \
4181 and asWords[0] == 'Opcode' \
4182 and ( asWords[1].startswith('0x')
4183 or asWords[1].startswith('0X')):
4184 asWords = asWords[:1];
4185 for iWord, sWord in enumerate(asWords):
4186 if sWord.startswith('0X'):
4187 sWord = '0x' + sWord[:2];
4188 asWords[iWord] = asWords;
4189 self.setInstrunctionAttrib('sRawOldOpcodes', ' '.join(asWords));
4190
4191 return False;
4192
4193 def ensureInstructionForOpTag(self, iTagLine):
4194 """ Ensure there is an instruction for the op-tag being parsed. """
4195 if not self.aoCurInstrs:
4196 self.addInstruction(self.iCommentLine + iTagLine);
4197 for oInstr in self.aoCurInstrs:
4198 oInstr.cOpTags += 1;
4199 if oInstr.cOpTags == 1:
4200 self.cTotalTagged += 1;
4201 return self.aoCurInstrs[-1];
4202
4203 @staticmethod
4204 def flattenSections(aasSections):
4205 """
4206 Flattens multiline sections into stripped single strings.
4207 Returns list of strings, on section per string.
4208 """
4209 asRet = [];
4210 for asLines in aasSections:
4211 if asLines:
4212 asRet.append(' '.join([sLine.strip() for sLine in asLines]));
4213 return asRet;
4214
4215 @staticmethod
4216 def flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = '\n'):
4217 """
4218 Flattens sections into a simple stripped string with newlines as
4219 section breaks. The final section does not sport a trailing newline.
4220 """
4221 # Typical: One section with a single line.
4222 if len(aasSections) == 1 and len(aasSections[0]) == 1:
4223 return aasSections[0][0].strip();
4224
4225 sRet = '';
4226 for iSection, asLines in enumerate(aasSections):
4227 if asLines:
4228 if iSection > 0:
4229 sRet += sSectionSep;
4230 sRet += sLineSep.join([sLine.strip() for sLine in asLines]);
4231 return sRet;
4232
4233
4234
4235 ## @name Tag parsers
4236 ## @{
4237
4238 def parseTagOpBrief(self, sTag, aasSections, iTagLine, iEndLine):
4239 """
4240 Tag: @opbrief
4241 Value: Text description, multiple sections, appended.
4242
4243 Brief description. If not given, it's the first sentence from @opdesc.
4244 """
4245 oInstr = self.ensureInstructionForOpTag(iTagLine);
4246
4247 # Flatten and validate the value.
4248 sBrief = self.flattenAllSections(aasSections);
4249 if not sBrief:
4250 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
4251 if sBrief[-1] != '.':
4252 sBrief = sBrief + '.';
4253 if len(sBrief) > 180:
4254 return self.errorComment(iTagLine, '%s: value too long (max 180 chars): %s' % (sTag, sBrief));
4255 offDot = sBrief.find('.');
4256 while 0 <= offDot < len(sBrief) - 1 and sBrief[offDot + 1] != ' ':
4257 offDot = sBrief.find('.', offDot + 1);
4258 if offDot >= 0 and offDot != len(sBrief) - 1:
4259 return self.errorComment(iTagLine, '%s: only one sentence: %s' % (sTag, sBrief));
4260
4261 # Update the instruction.
4262 if oInstr.sBrief is not None:
4263 return self.errorComment(iTagLine, '%s: attempting to overwrite brief "%s" with "%s"'
4264 % (sTag, oInstr.sBrief, sBrief,));
4265 _ = iEndLine;
4266 return True;
4267
4268 def parseTagOpDesc(self, sTag, aasSections, iTagLine, iEndLine):
4269 """
4270 Tag: @opdesc
4271 Value: Text description, multiple sections, appended.
4272
4273 It is used to describe instructions.
4274 """
4275 oInstr = self.ensureInstructionForOpTag(iTagLine);
4276 if aasSections:
4277 oInstr.asDescSections.extend(self.flattenSections(aasSections));
4278 return True;
4279
4280 _ = sTag; _ = iEndLine;
4281 return True;
4282
4283 def parseTagOpMnemonic(self, sTag, aasSections, iTagLine, iEndLine):
4284 """
4285 Tag: @opmenmonic
4286 Value: mnemonic
4287
4288 The 'mnemonic' value must be a valid C identifier string. Because of
4289 prefixes, groups and whatnot, there times when the mnemonic isn't that
4290 of an actual assembler mnemonic.
4291 """
4292 oInstr = self.ensureInstructionForOpTag(iTagLine);
4293
4294 # Flatten and validate the value.
4295 sMnemonic = self.flattenAllSections(aasSections);
4296 if not self.oReMnemonic.match(sMnemonic):
4297 return self.errorComment(iTagLine, '%s: invalid menmonic name: "%s"' % (sTag, sMnemonic,));
4298 if oInstr.sMnemonic is not None:
4299 return self.errorComment(iTagLine, '%s: attempting to overwrite menmonic "%s" with "%s"'
4300 % (sTag, oInstr.sMnemonic, sMnemonic,));
4301 oInstr.sMnemonic = sMnemonic
4302
4303 _ = iEndLine;
4304 return True;
4305
4306 def parseTagOpOperandN(self, sTag, aasSections, iTagLine, iEndLine):
4307 """
4308 Tags: @op1, @op2, @op3, @op4
4309 Value: [where:]type
4310
4311 The 'where' value indicates where the operand is found, like the 'reg'
4312 part of the ModR/M encoding. See Instruction.kdOperandLocations for
4313 a list.
4314
4315 The 'type' value indicates the operand type. These follow the types
4316 given in the opcode tables in the CPU reference manuals.
4317 See Instruction.kdOperandTypes for a list.
4318
4319 """
4320 oInstr = self.ensureInstructionForOpTag(iTagLine);
4321 idxOp = int(sTag[-1]) - 1;
4322 assert 0 <= idxOp < 4;
4323
4324 # flatten, split up, and validate the "where:type" value.
4325 sFlattened = self.flattenAllSections(aasSections);
4326 asSplit = sFlattened.split(':');
4327 if len(asSplit) == 1:
4328 sType = asSplit[0];
4329 sWhere = None;
4330 elif len(asSplit) == 2:
4331 (sWhere, sType) = asSplit;
4332 else:
4333 return self.errorComment(iTagLine, 'expected %s value on format "[<where>:]<type>" not "%s"' % (sTag, sFlattened,));
4334
4335 if sType not in g_kdOpTypes:
4336 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
4337 % (sTag, sType, ', '.join(g_kdOpTypes.keys()),));
4338 if sWhere is None:
4339 sWhere = g_kdOpTypes[sType][1];
4340 elif sWhere not in g_kdOpLocations:
4341 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
4342 % (sTag, sWhere, ', '.join(g_kdOpLocations.keys()),));
4343
4344 # Insert the operand, refusing to overwrite an existing one.
4345 while idxOp >= len(oInstr.aoOperands):
4346 oInstr.aoOperands.append(None);
4347 if oInstr.aoOperands[idxOp] is not None:
4348 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s:%s" with "%s:%s"'
4349 % ( sTag, oInstr.aoOperands[idxOp].sWhere, oInstr.aoOperands[idxOp].sType,
4350 sWhere, sType,));
4351 oInstr.aoOperands[idxOp] = Operand(sWhere, sType);
4352
4353 _ = iEndLine;
4354 return True;
4355
4356 def parseTagOpMaps(self, sTag, aasSections, iTagLine, iEndLine):
4357 """
4358 Tag: @opmaps
4359 Value: map[,map2]
4360
4361 Indicates which maps the instruction is in. There is a default map
4362 associated with each input file.
4363 """
4364 oInstr = self.ensureInstructionForOpTag(iTagLine);
4365
4366 # Flatten, split up and validate the value.
4367 sFlattened = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',');
4368 asMaps = sFlattened.split(',');
4369 if not asMaps:
4370 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
4371 for sMap in asMaps:
4372 if sMap not in g_dInstructionMaps:
4373 return self.errorComment(iTagLine, '%s: invalid map value: %s (valid values: %s)'
4374 % (sTag, sMap, ', '.join(g_dInstructionMaps.keys()),));
4375
4376 # Add the maps to the current list. Throw errors on duplicates.
4377 for oMap in oInstr.aoMaps:
4378 if oMap.sName in asMaps:
4379 return self.errorComment(iTagLine, '%s: duplicate map assignment: %s' % (sTag, oMap.sName));
4380
4381 for sMap in asMaps:
4382 oMap = g_dInstructionMaps[sMap];
4383 if oMap not in oInstr.aoMaps:
4384 oInstr.aoMaps.append(oMap);
4385 else:
4386 self.errorComment(iTagLine, '%s: duplicate map assignment (input): %s' % (sTag, sMap));
4387
4388 _ = iEndLine;
4389 return True;
4390
4391 def parseTagOpPfx(self, sTag, aasSections, iTagLine, iEndLine):
4392 """
4393 Tag: @oppfx
4394 Value: n/a|none|0x66|0xf3|0xf2|!0xf3
4395
4396 Required prefix for the instruction. (In a (E)VEX context this is the
4397 value of the 'pp' field rather than an actual prefix.)
4398 """
4399 oInstr = self.ensureInstructionForOpTag(iTagLine);
4400
4401 # Flatten and validate the value.
4402 sFlattened = self.flattenAllSections(aasSections);
4403 asPrefixes = sFlattened.split();
4404 if len(asPrefixes) > 1:
4405 return self.errorComment(iTagLine, '%s: max one prefix: %s' % (sTag, asPrefixes,));
4406
4407 sPrefix = asPrefixes[0].lower();
4408 if sPrefix == 'none':
4409 sPrefix = 'none';
4410 elif sPrefix == 'n/a':
4411 sPrefix = None;
4412 else:
4413 if len(sPrefix) == 2:
4414 sPrefix = '0x' + sPrefix;
4415 if not _isValidOpcodeByte(sPrefix):
4416 if sPrefix != '!0xf3':
4417 return self.errorComment(iTagLine, '%s: invalid prefix: %s' % (sTag, sPrefix,));
4418
4419 if sPrefix is not None and sPrefix not in g_kdPrefixes:
4420 return self.errorComment(iTagLine, '%s: invalid prefix: %s (valid %s)' % (sTag, sPrefix, g_kdPrefixes,));
4421
4422 # Set it.
4423 if oInstr.sPrefix is not None:
4424 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sPrefix, sPrefix,));
4425 oInstr.sPrefix = sPrefix;
4426
4427 _ = iEndLine;
4428 return True;
4429
4430 def parseTagOpcode(self, sTag, aasSections, iTagLine, iEndLine):
4431 """
4432 Tag: @opcode
4433 Value: 0x?? | /reg (TODO: | mr/reg | 11 /reg | !11 /reg | 11 mr/reg | !11 mr/reg)
4434
4435 The opcode byte or sub-byte for the instruction in the context of a map.
4436 """
4437 oInstr = self.ensureInstructionForOpTag(iTagLine);
4438
4439 # Flatten and validate the value.
4440 sOpcode = self.flattenAllSections(aasSections);
4441 if _isValidOpcodeByte(sOpcode):
4442 pass;
4443 elif len(sOpcode) == 2 and sOpcode.startswith('/') and sOpcode[-1] in '012345678':
4444 pass;
4445 elif len(sOpcode) == 4 and sOpcode.startswith('11/') and sOpcode[-1] in '012345678':
4446 pass;
4447 elif len(sOpcode) == 5 and sOpcode.startswith('!11/') and sOpcode[-1] in '012345678':
4448 pass;
4449 else:
4450 return self.errorComment(iTagLine, '%s: invalid opcode: %s' % (sTag, sOpcode,));
4451
4452 # Set it.
4453 if oInstr.sOpcode is not None:
4454 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sOpcode, sOpcode,));
4455 oInstr.sOpcode = sOpcode;
4456
4457 _ = iEndLine;
4458 return True;
4459
4460 def parseTagOpcodeSub(self, sTag, aasSections, iTagLine, iEndLine):
4461 """
4462 Tag: @opcodesub
4463 Value: none | 11 mr/reg | !11 mr/reg | rex.w=0 | rex.w=1 | vex.l=0 | vex.l=1
4464 | 11 mr/reg vex.l=0 | 11 mr/reg vex.l=1 | !11 mr/reg vex.l=0 | !11 mr/reg vex.l=1
4465 | !11 rex.w=0 | !11 mr/reg rex.w=0
4466 | !11 rex.w=1 | !11 mr/reg rex.w=1
4467
4468 This is a simple way of dealing with encodings where the mod=3 and mod!=3
4469 represents exactly two different instructions. The more proper way would
4470 be to go via maps with two members, but this is faster.
4471 """
4472 oInstr = self.ensureInstructionForOpTag(iTagLine);
4473
4474 # Flatten and validate the value.
4475 sSubOpcode = self.flattenAllSections(aasSections);
4476 if sSubOpcode not in g_kdSubOpcodes:
4477 return self.errorComment(iTagLine, '%s: invalid sub opcode: %s (valid: %s)'
4478 % (sTag, sSubOpcode, ', '.join(sorted(g_kdSubOpcodes.keys())),));
4479 sSubOpcode = g_kdSubOpcodes[sSubOpcode][0];
4480
4481 # Set it.
4482 if oInstr.sSubOpcode is not None:
4483 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4484 % ( sTag, oInstr.sSubOpcode, sSubOpcode,));
4485 oInstr.sSubOpcode = sSubOpcode;
4486
4487 _ = iEndLine;
4488 return True;
4489
4490 def parseTagOpEnc(self, sTag, aasSections, iTagLine, iEndLine):
4491 """
4492 Tag: @openc
4493 Value: ModR/M|fixed|prefix|<map name>
4494
4495 The instruction operand encoding style.
4496 """
4497 oInstr = self.ensureInstructionForOpTag(iTagLine);
4498
4499 # Flatten and validate the value.
4500 sEncoding = self.flattenAllSections(aasSections);
4501 if sEncoding in g_kdEncodings:
4502 pass;
4503 elif sEncoding in g_dInstructionMaps:
4504 pass;
4505 elif not _isValidOpcodeByte(sEncoding):
4506 return self.errorComment(iTagLine, '%s: invalid encoding: %s' % (sTag, sEncoding,));
4507
4508 # Set it.
4509 if oInstr.sEncoding is not None:
4510 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4511 % ( sTag, oInstr.sEncoding, sEncoding,));
4512 oInstr.sEncoding = sEncoding;
4513
4514 _ = iEndLine;
4515 return True;
4516
4517 ## EFlags tag to Instruction attribute name.
4518 kdOpFlagToAttr = {
4519 '@opfltest': 'asFlTest',
4520 '@opflmodify': 'asFlModify',
4521 '@opflundef': 'asFlUndefined',
4522 '@opflset': 'asFlSet',
4523 '@opflclear': 'asFlClear',
4524 };
4525
4526 def parseTagOpEFlags(self, sTag, aasSections, iTagLine, iEndLine):
4527 """
4528 Tags: @opfltest, @opflmodify, @opflundef, @opflset, @opflclear
4529 Value: <eflags specifier>
4530
4531 """
4532 oInstr = self.ensureInstructionForOpTag(iTagLine);
4533
4534 # Flatten, split up and validate the values.
4535 asFlags = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',').split(',');
4536 if len(asFlags) == 1 and asFlags[0].lower() == 'none':
4537 asFlags = [];
4538 else:
4539 fRc = True;
4540 for iFlag, sFlag in enumerate(asFlags):
4541 if sFlag not in g_kdEFlagsMnemonics:
4542 if sFlag.strip() in g_kdEFlagsMnemonics:
4543 asFlags[iFlag] = sFlag.strip();
4544 else:
4545 fRc = self.errorComment(iTagLine, '%s: invalid EFLAGS value: %s' % (sTag, sFlag,));
4546 if not fRc:
4547 return False;
4548
4549 # Set them.
4550 asOld = getattr(oInstr, self.kdOpFlagToAttr[sTag]);
4551 if asOld is not None and len(asOld) > 0:
4552 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, asOld, asFlags,));
4553 setattr(oInstr, self.kdOpFlagToAttr[sTag], asFlags);
4554
4555 _ = iEndLine;
4556 return True;
4557
4558 ## EFLAGS class definitions with their attribute lists.
4559 kdEFlagsClasses = {
4560 'arithmetic': { # add, sub, ...
4561 'asFlTest': [],
4562 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4563 'asFlClear': [],
4564 'asFlSet': [],
4565 'asFlUndefined': [],
4566 },
4567 'arithmetic_carry': { # adc, sbb, ...
4568 'asFlTest': [ 'cf', ],
4569 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4570 'asFlClear': [],
4571 'asFlSet': [],
4572 'asFlUndefined': [],
4573 },
4574 'incdec': {
4575 'asFlTest': [],
4576 'asFlModify': [ 'pf', 'af', 'zf', 'sf', 'of', ], # leaves CF alone
4577 'asFlClear': [],
4578 'asFlSet': [],
4579 'asFlUndefined': [],
4580 },
4581 'division': { ## @todo specify intel/amd differences...
4582 'asFlTest': [ 'pf', 'af', 'zf', 'sf', ], # Intel leaves all flags unchanged.
4583 'asFlModify': [ 'pf', 'af', 'zf', 'sf', ], # While AMD sets AF and clears PF, ZF & SF, leaving CF and OF alone.
4584 'asFlClear': [],
4585 'asFlSet': [],
4586 'asFlUndefined': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4587 },
4588 'multiply': { ## @todo specify intel/amd differences...
4589 'asFlTest': [ 'pf', 'af', 'zf', 'sf', ], # AMD leaves these unchanged, so we have to delcare them as inputs.
4590 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of' ], # Intel always modifies all flags, but how differs
4591 'asFlClear': [], # between IMUL and MUL.
4592 'asFlSet': [],
4593 'asFlUndefined': [ 'pf', 'af', 'zf', 'sf', ],
4594 },
4595 'logical': { # and, or, xor, ...
4596 'asFlTest': [],
4597 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4598 'asFlClear': [ 'cf', 'af', 'of', ], # 'af' is undefined, but tstIEMAImpl indicates that it is cleared.
4599 'asFlSet': [],
4600 'asFlUndefined': [ 'af', ],
4601 },
4602 'rotate_1': { # rol and ror with fixed 1 shift count
4603 'asFlTest': [],
4604 'asFlModify': [ 'cf', 'of', ],
4605 'asFlClear': [],
4606 'asFlSet': [],
4607 'asFlUndefined': [],
4608 },
4609 'rotate_count': { # rol and ror w/o fixed 1 shift count
4610 'asFlTest': [ 'cf', 'of', ], # If the count is zero, nothing changes.
4611 'asFlModify': [ 'cf', 'of', ],
4612 'asFlClear': [],
4613 'asFlSet': [],
4614 'asFlUndefined': [ 'of', ],
4615 },
4616 'rotate_carry_1': { # rcl and rcr with fixed 1 shift count
4617 'asFlTest': [ 'cf', ],
4618 'asFlModify': [ 'cf', 'of', ],
4619 'asFlClear': [],
4620 'asFlSet': [],
4621 'asFlUndefined': [],
4622 },
4623 'rotate_carry_count': { # rcl and rcr w/o fixed 1 shift count
4624 'asFlTest': [ 'cf', 'of', ], # If the count is zero, nothing changes, so 'of' is also input.
4625 'asFlModify': [ 'cf', 'of', ],
4626 'asFlClear': [],
4627 'asFlSet': [],
4628 'asFlUndefined': [ 'of', ],
4629 },
4630 'shift_1': { # shl, shr or sar with fixed 1 count.
4631 'asFlTest': [],
4632 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4633 'asFlClear': [],
4634 'asFlSet': [],
4635 'asFlUndefined': [ 'af', ],
4636 },
4637 'shift_count': { # shl, shr or sar w/o fixed 1 shift count
4638 'asFlTest': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ], # If the count is zero, nothing is changed.
4639 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4640 'asFlClear': [],
4641 'asFlSet': [],
4642 'asFlUndefined': [ 'af', 'of', ],
4643 },
4644 'bitmap': { # bt, btc, btr, btc
4645 'asFlTest': [],
4646 'asFlModify': [ 'cf', ],
4647 'asFlClear': [],
4648 'asFlSet': [],
4649 'asFlUndefined': [ 'pf', 'af', 'zf', 'sf', 'of', ], # tstIEMAImpl indicates that they aren't modified.
4650 },
4651 'unchanged': {
4652 'asFlTest': [],
4653 'asFlModify': [],
4654 'asFlClear': [],
4655 'asFlSet': [],
4656 'asFlUndefined': [],
4657 },
4658 };
4659 def parseTagOpEFlagsClass(self, sTag, aasSections, iTagLine, iEndLine):
4660 """
4661 Tags: @opflclass
4662 Value: arithmetic, logical, ...
4663
4664 """
4665 oInstr = self.ensureInstructionForOpTag(iTagLine);
4666
4667 # Flatten and validate the value.
4668 sClass = self.flattenAllSections(aasSections);
4669 kdAttribs = self.kdEFlagsClasses.get(sClass);
4670 if not kdAttribs:
4671 return self.errorComment(iTagLine, '%s: Unknown EFLAGS class: %s (valid: %s)'
4672 % (sTag, sClass, ', '.join(sorted(self.kdEFlagsClasses.keys())),));
4673
4674 # Set the attributes.
4675 for sAttrib, asFlags in kdAttribs.items():
4676 asOld = getattr(oInstr, sAttrib);
4677 if asOld is not None:
4678 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s" for %s'
4679 % (sTag, asOld, asFlags, sAttrib));
4680 setattr(oInstr, sAttrib, asFlags);
4681
4682 _ = iEndLine;
4683 return True;
4684
4685 def parseTagOpHints(self, sTag, aasSections, iTagLine, iEndLine):
4686 """
4687 Tag: @ophints
4688 Value: Comma or space separated list of flags and hints.
4689
4690 This covers the disassembler flags table and more.
4691 """
4692 oInstr = self.ensureInstructionForOpTag(iTagLine);
4693
4694 # Flatten as a space separated list, split it up and validate the values.
4695 asHints = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4696 if len(asHints) == 1 and asHints[0].lower() == 'none':
4697 asHints = [];
4698 else:
4699 fRc = True;
4700 for iHint, sHint in enumerate(asHints):
4701 if sHint not in g_kdHints:
4702 if sHint.strip() in g_kdHints:
4703 sHint[iHint] = sHint.strip();
4704 else:
4705 fRc = self.errorComment(iTagLine, '%s: invalid hint value: %s' % (sTag, sHint,));
4706 if not fRc:
4707 return False;
4708
4709 # Append them.
4710 for sHint in asHints:
4711 if sHint not in oInstr.dHints:
4712 oInstr.dHints[sHint] = True; # (dummy value, using dictionary for speed)
4713 else:
4714 self.errorComment(iTagLine, '%s: duplicate hint: %s' % ( sTag, sHint,));
4715
4716 _ = iEndLine;
4717 return True;
4718
4719 def parseTagOpDisEnum(self, sTag, aasSections, iTagLine, iEndLine):
4720 """
4721 Tag: @opdisenum
4722 Value: OP_XXXX
4723
4724 This is for select a specific (legacy) disassembler enum value for the
4725 instruction.
4726 """
4727 oInstr = self.ensureInstructionForOpTag(iTagLine);
4728
4729 # Flatten and split.
4730 asWords = self.flattenAllSections(aasSections).split();
4731 if len(asWords) != 1:
4732 self.errorComment(iTagLine, '%s: expected exactly one value: %s' % (sTag, asWords,));
4733 if not asWords:
4734 return False;
4735 sDisEnum = asWords[0];
4736 if not self.oReDisEnum.match(sDisEnum):
4737 return self.errorComment(iTagLine, '%s: invalid disassembler OP_XXXX enum: %s (pattern: %s)'
4738 % (sTag, sDisEnum, self.oReDisEnum.pattern));
4739
4740 # Set it.
4741 if oInstr.sDisEnum is not None:
4742 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % (sTag, oInstr.sDisEnum, sDisEnum,));
4743 oInstr.sDisEnum = sDisEnum;
4744
4745 _ = iEndLine;
4746 return True;
4747
4748 def parseTagOpMinCpu(self, sTag, aasSections, iTagLine, iEndLine):
4749 """
4750 Tag: @opmincpu
4751 Value: <simple CPU name>
4752
4753 Indicates when this instruction was introduced.
4754 """
4755 oInstr = self.ensureInstructionForOpTag(iTagLine);
4756
4757 # Flatten the value, split into words, make sure there's just one, valid it.
4758 asCpus = self.flattenAllSections(aasSections).split();
4759 if len(asCpus) > 1:
4760 self.errorComment(iTagLine, '%s: exactly one CPU name, please: %s' % (sTag, ' '.join(asCpus),));
4761
4762 sMinCpu = asCpus[0];
4763 if sMinCpu in g_kdCpuNames:
4764 oInstr.sMinCpu = sMinCpu;
4765 else:
4766 return self.errorComment(iTagLine, '%s: invalid CPU name: %s (names: %s)'
4767 % (sTag, sMinCpu, ','.join(sorted(g_kdCpuNames)),));
4768
4769 # Set it.
4770 if oInstr.sMinCpu is None:
4771 oInstr.sMinCpu = sMinCpu;
4772 elif oInstr.sMinCpu != sMinCpu:
4773 self.errorComment(iTagLine, '%s: attemting to overwrite "%s" with "%s"' % (sTag, oInstr.sMinCpu, sMinCpu,));
4774
4775 _ = iEndLine;
4776 return True;
4777
4778 def parseTagOpCpuId(self, sTag, aasSections, iTagLine, iEndLine):
4779 """
4780 Tag: @opcpuid
4781 Value: none | <CPUID flag specifier>
4782
4783 CPUID feature bit which is required for the instruction to be present.
4784 """
4785 oInstr = self.ensureInstructionForOpTag(iTagLine);
4786
4787 # Flatten as a space separated list, split it up and validate the values.
4788 asCpuIds = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4789 if len(asCpuIds) == 1 and asCpuIds[0].lower() == 'none':
4790 asCpuIds = [];
4791 else:
4792 fRc = True;
4793 for iCpuId, sCpuId in enumerate(asCpuIds):
4794 if sCpuId not in g_kdCpuIdFlags:
4795 if sCpuId.strip() in g_kdCpuIdFlags:
4796 sCpuId[iCpuId] = sCpuId.strip();
4797 else:
4798 fRc = self.errorComment(iTagLine, '%s: invalid CPUID value: %s' % (sTag, sCpuId,));
4799 if not fRc:
4800 return False;
4801
4802 # Append them.
4803 for sCpuId in asCpuIds:
4804 if sCpuId not in oInstr.asCpuIds:
4805 oInstr.asCpuIds.append(sCpuId);
4806 else:
4807 self.errorComment(iTagLine, '%s: duplicate CPUID: %s' % ( sTag, sCpuId,));
4808
4809 _ = iEndLine;
4810 return True;
4811
4812 def parseTagOpGroup(self, sTag, aasSections, iTagLine, iEndLine):
4813 """
4814 Tag: @opgroup
4815 Value: op_grp1[_subgrp2[_subsubgrp3]]
4816
4817 Instruction grouping.
4818 """
4819 oInstr = self.ensureInstructionForOpTag(iTagLine);
4820
4821 # Flatten as a space separated list, split it up and validate the values.
4822 asGroups = self.flattenAllSections(aasSections).split();
4823 if len(asGroups) != 1:
4824 return self.errorComment(iTagLine, '%s: exactly one group, please: %s' % (sTag, asGroups,));
4825 sGroup = asGroups[0];
4826 if not self.oReGroupName.match(sGroup):
4827 return self.errorComment(iTagLine, '%s: invalid group name: %s (valid: %s)'
4828 % (sTag, sGroup, self.oReGroupName.pattern));
4829
4830 # Set it.
4831 if oInstr.sGroup is not None:
4832 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sGroup, sGroup,));
4833 oInstr.sGroup = sGroup;
4834
4835 _ = iEndLine;
4836 return True;
4837
4838 def parseTagOpUnusedInvalid(self, sTag, aasSections, iTagLine, iEndLine):
4839 """
4840 Tag: @opunused, @opinvalid, @opinvlstyle
4841 Value: <invalid opcode behaviour style>
4842
4843 The @opunused indicates the specification is for a currently unused
4844 instruction encoding.
4845
4846 The @opinvalid indicates the specification is for an invalid currently
4847 instruction encoding (like UD2).
4848
4849 The @opinvlstyle just indicates how CPUs decode the instruction when
4850 not supported (@opcpuid, @opmincpu) or disabled.
4851 """
4852 oInstr = self.ensureInstructionForOpTag(iTagLine);
4853
4854 # Flatten as a space separated list, split it up and validate the values.
4855 asStyles = self.flattenAllSections(aasSections).split();
4856 if len(asStyles) != 1:
4857 return self.errorComment(iTagLine, '%s: exactly one invalid behviour style, please: %s' % (sTag, asStyles,));
4858 sStyle = asStyles[0];
4859 if sStyle not in g_kdInvalidStyles:
4860 return self.errorComment(iTagLine, '%s: invalid invalid behaviour style: %s (valid: %s)'
4861 % (sTag, sStyle, g_kdInvalidStyles.keys(),));
4862 # Set it.
4863 if oInstr.sInvalidStyle is not None:
4864 return self.errorComment(iTagLine,
4865 '%s: attempting to overwrite "%s" with "%s" (only one @opunused, @opinvalid, @opinvlstyle)'
4866 % ( sTag, oInstr.sInvalidStyle, sStyle,));
4867 oInstr.sInvalidStyle = sStyle;
4868 if sTag == '@opunused':
4869 oInstr.fUnused = True;
4870 elif sTag == '@opinvalid':
4871 oInstr.fInvalid = True;
4872
4873 _ = iEndLine;
4874 return True;
4875
4876 def parseTagOpTest(self, sTag, aasSections, iTagLine, iEndLine): # pylint: disable=too-many-locals
4877 """
4878 Tag: @optest
4879 Value: [<selectors>[ ]?] <inputs> -> <outputs>
4880 Example: mode==64bit / in1=0xfffffffe:dw in2=1:dw -> out1=0xffffffff:dw outfl=a?,p?
4881
4882 The main idea here is to generate basic instruction tests.
4883
4884 The probably simplest way of handling the diverse input, would be to use
4885 it to produce size optimized byte code for a simple interpreter that
4886 modifies the register input and output states.
4887
4888 An alternative to the interpreter would be creating multiple tables,
4889 but that becomes rather complicated wrt what goes where and then to use
4890 them in an efficient manner.
4891 """
4892 oInstr = self.ensureInstructionForOpTag(iTagLine);
4893
4894 #
4895 # Do it section by section.
4896 #
4897 for asSectionLines in aasSections:
4898 #
4899 # Sort the input into outputs, inputs and selector conditions.
4900 #
4901 sFlatSection = self.flattenAllSections([asSectionLines,]);
4902 if not sFlatSection:
4903 self.errorComment(iTagLine, '%s: missing value (dbg: aasSections=%s)' % ( sTag, aasSections));
4904 continue;
4905 oTest = InstructionTest(oInstr);
4906
4907 asSelectors = [];
4908 asInputs = [];
4909 asOutputs = [];
4910 asCur = asOutputs;
4911 fRc = True;
4912 asWords = sFlatSection.split();
4913 for iWord in range(len(asWords) - 1, -1, -1):
4914 sWord = asWords[iWord];
4915 # Check for array switchers.
4916 if sWord == '->':
4917 if asCur != asOutputs:
4918 fRc = self.errorComment(iTagLine, '%s: "->" shall only occure once: %s' % (sTag, sFlatSection,));
4919 break;
4920 asCur = asInputs;
4921 elif sWord == '/':
4922 if asCur != asInputs:
4923 fRc = self.errorComment(iTagLine, '%s: "/" shall only occure once: %s' % (sTag, sFlatSection,));
4924 break;
4925 asCur = asSelectors;
4926 else:
4927 asCur.insert(0, sWord);
4928
4929 #
4930 # Validate and add selectors.
4931 #
4932 for sCond in asSelectors:
4933 sCondExp = TestSelector.kdPredicates.get(sCond, sCond);
4934 oSelector = None;
4935 for sOp in TestSelector.kasCompareOps:
4936 off = sCondExp.find(sOp);
4937 if off >= 0:
4938 sVariable = sCondExp[:off];
4939 sValue = sCondExp[off + len(sOp):];
4940 if sVariable in TestSelector.kdVariables:
4941 if sValue in TestSelector.kdVariables[sVariable]:
4942 oSelector = TestSelector(sVariable, sOp, sValue);
4943 else:
4944 self.errorComment(iTagLine, '%s: invalid condition value "%s" in "%s" (valid: %s)'
4945 % ( sTag, sValue, sCond,
4946 TestSelector.kdVariables[sVariable].keys(),));
4947 else:
4948 self.errorComment(iTagLine, '%s: invalid condition variable "%s" in "%s" (valid: %s)'
4949 % ( sTag, sVariable, sCond, TestSelector.kdVariables.keys(),));
4950 break;
4951 if oSelector is not None:
4952 for oExisting in oTest.aoSelectors:
4953 if oExisting.sVariable == oSelector.sVariable:
4954 self.errorComment(iTagLine, '%s: already have a selector for variable "%s" (existing: %s, new: %s)'
4955 % ( sTag, oSelector.sVariable, oExisting, oSelector,));
4956 oTest.aoSelectors.append(oSelector);
4957 else:
4958 fRc = self.errorComment(iTagLine, '%s: failed to parse selector: %s' % ( sTag, sCond,));
4959
4960 #
4961 # Validate outputs and inputs, adding them to the test as we go along.
4962 #
4963 for asItems, sDesc, aoDst in [ (asInputs, 'input', oTest.aoInputs), (asOutputs, 'output', oTest.aoOutputs)]:
4964 asValidFieldKinds = [ 'both', sDesc, ];
4965 for sItem in asItems:
4966 oItem = None;
4967 for sOp in TestInOut.kasOperators:
4968 off = sItem.find(sOp);
4969 if off < 0:
4970 continue;
4971 sField = sItem[:off];
4972 sValueType = sItem[off + len(sOp):];
4973 if sField in TestInOut.kdFields \
4974 and TestInOut.kdFields[sField][1] in asValidFieldKinds:
4975 asSplit = sValueType.split(':', 1);
4976 sValue = asSplit[0];
4977 sType = asSplit[1] if len(asSplit) > 1 else TestInOut.kdFields[sField][0];
4978 if sType in TestInOut.kdTypes:
4979 oValid = TestInOut.kdTypes[sType].validate(sValue);
4980 if oValid is True:
4981 if not TestInOut.kdTypes[sType].isAndOrPair(sValue) or sOp == '&|=':
4982 oItem = TestInOut(sField, sOp, sValue, sType);
4983 else:
4984 self.errorComment(iTagLine, '%s: and-or %s value "%s" can only be used with "&|="'
4985 % ( sTag, sDesc, sItem, ));
4986 else:
4987 self.errorComment(iTagLine, '%s: invalid %s value "%s" in "%s" (type: %s): %s'
4988 % ( sTag, sDesc, sValue, sItem, sType, oValid, ));
4989 else:
4990 self.errorComment(iTagLine, '%s: invalid %s type "%s" in "%s" (valid types: %s)'
4991 % ( sTag, sDesc, sType, sItem, TestInOut.kdTypes.keys(),));
4992 else:
4993 self.errorComment(iTagLine, '%s: invalid %s field "%s" in "%s"\nvalid fields: %s'
4994 % ( sTag, sDesc, sField, sItem,
4995 ', '.join([sKey for sKey, asVal in TestInOut.kdFields.items()
4996 if asVal[1] in asValidFieldKinds]),));
4997 break;
4998 if oItem is not None:
4999 for oExisting in aoDst:
5000 if oExisting.sField == oItem.sField and oExisting.sOp == oItem.sOp:
5001 self.errorComment(iTagLine,
5002 '%s: already have a "%s" assignment for field "%s" (existing: %s, new: %s)'
5003 % ( sTag, oItem.sOp, oItem.sField, oExisting, oItem,));
5004 aoDst.append(oItem);
5005 else:
5006 fRc = self.errorComment(iTagLine, '%s: failed to parse assignment: %s' % ( sTag, sItem,));
5007
5008 #
5009 # .
5010 #
5011 if fRc:
5012 oInstr.aoTests.append(oTest);
5013 else:
5014 self.errorComment(iTagLine, '%s: failed to parse test: %s' % (sTag, ' '.join(asWords),));
5015 self.errorComment(iTagLine, '%s: asSelectors=%s / asInputs=%s -> asOutputs=%s'
5016 % (sTag, asSelectors, asInputs, asOutputs,));
5017
5018 _ = iEndLine;
5019 return True;
5020
5021 def parseTagOpTestNum(self, sTag, aasSections, iTagLine, iEndLine):
5022 """
5023 Numbered @optest tag. Either @optest42 or @optest[42].
5024 """
5025 oInstr = self.ensureInstructionForOpTag(iTagLine);
5026
5027 iTest = 0;
5028 if sTag[-1] == ']':
5029 iTest = int(sTag[8:-1]);
5030 else:
5031 iTest = int(sTag[7:]);
5032
5033 if iTest != len(oInstr.aoTests):
5034 self.errorComment(iTagLine, '%s: incorrect test number: %u, actual %u' % (sTag, iTest, len(oInstr.aoTests),));
5035 return self.parseTagOpTest(sTag, aasSections, iTagLine, iEndLine);
5036
5037 def parseTagOpTestIgnore(self, sTag, aasSections, iTagLine, iEndLine):
5038 """
5039 Tag: @optestign | @optestignore
5040 Value: <value is ignored>
5041
5042 This is a simple trick to ignore a test while debugging another.
5043
5044 See also @oponlytest.
5045 """
5046 _ = sTag; _ = aasSections; _ = iTagLine; _ = iEndLine;
5047 return True;
5048
5049 def parseTagOpCopyTests(self, sTag, aasSections, iTagLine, iEndLine):
5050 """
5051 Tag: @opcopytests
5052 Value: <opstat | function> [..]
5053 Example: @opcopytests add_Eb_Gb
5054
5055 Trick to avoid duplicating tests for different encodings of the same
5056 operation.
5057 """
5058 oInstr = self.ensureInstructionForOpTag(iTagLine);
5059
5060 # Flatten, validate and append the copy job to the instruction. We execute
5061 # them after parsing all the input so we can handle forward references.
5062 asToCopy = self.flattenAllSections(aasSections).split();
5063 if not asToCopy:
5064 return self.errorComment(iTagLine, '%s: requires at least on reference value' % (sTag,));
5065 for sToCopy in asToCopy:
5066 if sToCopy not in oInstr.asCopyTests:
5067 if self.oReStatsName.match(sToCopy) or self.oReFunctionName.match(sToCopy):
5068 oInstr.asCopyTests.append(sToCopy);
5069 else:
5070 self.errorComment(iTagLine, '%s: invalid instruction reference (opstat or function) "%s" (valid: %s or %s)'
5071 % (sTag, sToCopy, self.oReStatsName.pattern, self.oReFunctionName.pattern));
5072 else:
5073 self.errorComment(iTagLine, '%s: ignoring duplicate "%s"' % (sTag, sToCopy,));
5074
5075 _ = iEndLine;
5076 return True;
5077
5078 def parseTagOpOnlyTest(self, sTag, aasSections, iTagLine, iEndLine):
5079 """
5080 Tag: @oponlytest | @oponly
5081 Value: none
5082
5083 Only test instructions with this tag. This is a trick that is handy
5084 for singling out one or two new instructions or tests.
5085
5086 See also @optestignore.
5087 """
5088 oInstr = self.ensureInstructionForOpTag(iTagLine);
5089
5090 # Validate and add instruction to only test dictionary.
5091 sValue = self.flattenAllSections(aasSections).strip();
5092 if sValue:
5093 return self.errorComment(iTagLine, '%s: does not take any value: %s' % (sTag, sValue));
5094
5095 if oInstr not in g_aoOnlyTestInstructions:
5096 g_aoOnlyTestInstructions.append(oInstr);
5097
5098 _ = iEndLine;
5099 return True;
5100
5101 def parseTagOpXcptType(self, sTag, aasSections, iTagLine, iEndLine):
5102 """
5103 Tag: @opxcpttype
5104 Value: [none|1|2|3|4|4UA|5|6|7|8|11|12|E1|E1NF|E2|E3|E3NF|E4|E4NF|E5|E5NF|E6|E6NF|E7NF|E9|E9NF|E10|E11|E12|E12NF]
5105
5106 Sets the SSE or AVX exception type (see SDMv2 2.4, 2.7).
5107 """
5108 oInstr = self.ensureInstructionForOpTag(iTagLine);
5109
5110 # Flatten as a space separated list, split it up and validate the values.
5111 asTypes = self.flattenAllSections(aasSections).split();
5112 if len(asTypes) != 1:
5113 return self.errorComment(iTagLine, '%s: exactly one invalid exception type, please: %s' % (sTag, asTypes,));
5114 sType = asTypes[0];
5115 if sType not in g_kdXcptTypes:
5116 return self.errorComment(iTagLine, '%s: invalid invalid exception type: %s (valid: %s)'
5117 % (sTag, sType, sorted(g_kdXcptTypes.keys()),));
5118 # Set it.
5119 if oInstr.sXcptType is not None:
5120 return self.errorComment(iTagLine,
5121 '%s: attempting to overwrite "%s" with "%s" (only one @opxcpttype)'
5122 % ( sTag, oInstr.sXcptType, sType,));
5123 oInstr.sXcptType = sType;
5124
5125 _ = iEndLine;
5126 return True;
5127
5128 def parseTagOpFunction(self, sTag, aasSections, iTagLine, iEndLine):
5129 """
5130 Tag: @opfunction
5131 Value: <VMM function name>
5132
5133 This is for explicitly setting the IEM function name. Normally we pick
5134 this up from the FNIEMOP_XXX macro invocation after the description, or
5135 generate it from the mnemonic and operands.
5136
5137 It it thought it maybe necessary to set it when specifying instructions
5138 which implementation isn't following immediately or aren't implemented yet.
5139 """
5140 oInstr = self.ensureInstructionForOpTag(iTagLine);
5141
5142 # Flatten and validate the value.
5143 sFunction = self.flattenAllSections(aasSections);
5144 if not self.oReFunctionName.match(sFunction):
5145 return self.errorComment(iTagLine, '%s: invalid VMM function name: "%s" (valid: %s)'
5146 % (sTag, sFunction, self.oReFunctionName.pattern));
5147
5148 if oInstr.sFunction is not None:
5149 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM function name "%s" with "%s"'
5150 % (sTag, oInstr.sFunction, sFunction,));
5151 oInstr.sFunction = sFunction;
5152
5153 _ = iEndLine;
5154 return True;
5155
5156 def parseTagOpStats(self, sTag, aasSections, iTagLine, iEndLine):
5157 """
5158 Tag: @opstats
5159 Value: <VMM statistics base name>
5160
5161 This is for explicitly setting the statistics name. Normally we pick
5162 this up from the IEMOP_MNEMONIC macro invocation, or generate it from
5163 the mnemonic and operands.
5164
5165 It it thought it maybe necessary to set it when specifying instructions
5166 which implementation isn't following immediately or aren't implemented yet.
5167 """
5168 oInstr = self.ensureInstructionForOpTag(iTagLine);
5169
5170 # Flatten and validate the value.
5171 sStats = self.flattenAllSections(aasSections);
5172 if not self.oReStatsName.match(sStats):
5173 return self.errorComment(iTagLine, '%s: invalid VMM statistics name: "%s" (valid: %s)'
5174 % (sTag, sStats, self.oReStatsName.pattern));
5175
5176 if oInstr.sStats is not None:
5177 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM statistics base name "%s" with "%s"'
5178 % (sTag, oInstr.sStats, sStats,));
5179 oInstr.sStats = sStats;
5180
5181 _ = iEndLine;
5182 return True;
5183
5184 def parseTagOpDone(self, sTag, aasSections, iTagLine, iEndLine):
5185 """
5186 Tag: @opdone
5187 Value: none
5188
5189 Used to explictily flush the instructions that have been specified.
5190 """
5191 sFlattened = self.flattenAllSections(aasSections);
5192 if sFlattened != '':
5193 return self.errorComment(iTagLine, '%s: takes no value, found: "%s"' % (sTag, sFlattened,));
5194 _ = sTag; _ = iEndLine;
5195 return self.doneInstructions();
5196
5197 ## @}
5198
5199
5200 def parseComment(self):
5201 """
5202 Parse the current comment (self.sComment).
5203
5204 If it's a opcode specifiying comment, we reset the macro stuff.
5205 """
5206 #
5207 # Reject if comment doesn't seem to contain anything interesting.
5208 #
5209 if self.sComment.find('Opcode') < 0 \
5210 and self.sComment.find('@') < 0:
5211 return False;
5212
5213 #
5214 # Split the comment into lines, removing leading asterisks and spaces.
5215 # Also remove leading and trailing empty lines.
5216 #
5217 asLines = self.sComment.split('\n');
5218 for iLine, sLine in enumerate(asLines):
5219 asLines[iLine] = sLine.lstrip().lstrip('*').lstrip();
5220
5221 while asLines and not asLines[0]:
5222 self.iCommentLine += 1;
5223 asLines.pop(0);
5224
5225 while asLines and not asLines[-1]:
5226 asLines.pop(len(asLines) - 1);
5227
5228 #
5229 # Check for old style: Opcode 0x0f 0x12
5230 #
5231 if asLines[0].startswith('Opcode '):
5232 self.parseCommentOldOpcode(asLines);
5233
5234 #
5235 # Look for @op* tagged data.
5236 #
5237 cOpTags = 0;
5238 sFlatDefault = None;
5239 sCurTag = '@default';
5240 iCurTagLine = 0;
5241 asCurSection = [];
5242 aasSections = [ asCurSection, ];
5243 for iLine, sLine in enumerate(asLines):
5244 if not sLine.startswith('@'):
5245 if sLine:
5246 asCurSection.append(sLine);
5247 elif asCurSection:
5248 asCurSection = [];
5249 aasSections.append(asCurSection);
5250 else:
5251 #
5252 # Process the previous tag.
5253 #
5254 if not asCurSection and len(aasSections) > 1:
5255 aasSections.pop(-1);
5256 if sCurTag in self.dTagHandlers:
5257 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
5258 cOpTags += 1;
5259 elif sCurTag.startswith('@op'):
5260 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
5261 elif sCurTag == '@default':
5262 sFlatDefault = self.flattenAllSections(aasSections);
5263 elif '@op' + sCurTag[1:] in self.dTagHandlers:
5264 self.errorComment(iCurTagLine, 'Did you mean "@op%s" rather than "%s"?' % (sCurTag[1:], sCurTag));
5265 elif sCurTag in ['@encoding', '@opencoding']:
5266 self.errorComment(iCurTagLine, 'Did you mean "@openc" rather than "%s"?' % (sCurTag,));
5267
5268 #
5269 # New tag.
5270 #
5271 asSplit = sLine.split(None, 1);
5272 sCurTag = asSplit[0].lower();
5273 if len(asSplit) > 1:
5274 asCurSection = [asSplit[1],];
5275 else:
5276 asCurSection = [];
5277 aasSections = [asCurSection, ];
5278 iCurTagLine = iLine;
5279
5280 #
5281 # Process the final tag.
5282 #
5283 if not asCurSection and len(aasSections) > 1:
5284 aasSections.pop(-1);
5285 if sCurTag in self.dTagHandlers:
5286 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
5287 cOpTags += 1;
5288 elif sCurTag.startswith('@op'):
5289 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
5290 elif sCurTag == '@default':
5291 sFlatDefault = self.flattenAllSections(aasSections);
5292
5293 #
5294 # Don't allow default text in blocks containing @op*.
5295 #
5296 if cOpTags > 0 and sFlatDefault:
5297 self.errorComment(0, 'Untagged comment text is not allowed with @op*: %s' % (sFlatDefault,));
5298
5299 return True;
5300
5301 def parseMacroInvocation(self, sInvocation, offStartInvocation = 0):
5302 """
5303 Parses a macro invocation.
5304
5305 Returns three values:
5306 1. A list of macro arguments, where the zero'th is the macro name.
5307 2. The offset following the macro invocation, into sInvocation of
5308 this is on the same line or into the last line if it is on a
5309 different line.
5310 3. Number of additional lines the invocation spans (i.e. zero if
5311 it is all contained within sInvocation).
5312 """
5313 # First the name.
5314 offOpen = sInvocation.find('(', offStartInvocation);
5315 if offOpen <= offStartInvocation:
5316 self.raiseError("macro invocation open parenthesis not found");
5317 sName = sInvocation[offStartInvocation:offOpen].strip();
5318 if not self.oReMacroName.match(sName):
5319 self.raiseError("invalid macro name '%s'" % (sName,));
5320 asRet = [sName, ];
5321
5322 # Arguments.
5323 iLine = self.iLine;
5324 cDepth = 1;
5325 off = offOpen + 1;
5326 offStart = off;
5327 offCurLn = 0;
5328 chQuote = None;
5329 while cDepth > 0:
5330 if off >= len(sInvocation):
5331 if iLine >= len(self.asLines):
5332 self.error('macro invocation beyond end of file');
5333 return (asRet, off - offCurLn, iLine - self.iLine);
5334 offCurLn = off;
5335 sInvocation += self.asLines[iLine];
5336 iLine += 1;
5337 ch = sInvocation[off];
5338
5339 if chQuote:
5340 if ch == '\\' and off + 1 < len(sInvocation):
5341 off += 1;
5342 elif ch == chQuote:
5343 chQuote = None;
5344 elif ch in ('"', '\'',):
5345 chQuote = ch;
5346 elif ch in (',', ')',):
5347 if cDepth == 1:
5348 asRet.append(sInvocation[offStart:off].strip());
5349 offStart = off + 1;
5350 if ch == ')':
5351 cDepth -= 1;
5352 elif ch == '(':
5353 cDepth += 1;
5354 off += 1;
5355
5356 return (asRet, off - offCurLn, iLine - self.iLine);
5357
5358 def findAndParseMacroInvocationEx(self, sCode, sMacro, offStart = 0):
5359 """
5360 Returns (None, len(sCode), 0) if not found, otherwise the
5361 parseMacroInvocation() return value.
5362 """
5363 offHit = sCode.find(sMacro, offStart);
5364 if offHit >= 0 and sCode[offHit + len(sMacro):].strip()[0] == '(':
5365 return self.parseMacroInvocation(sCode, offHit);
5366 return (None, len(sCode), 0);
5367
5368 def findAndParseMacroInvocation(self, sCode, sMacro):
5369 """
5370 Returns None if not found, arguments as per parseMacroInvocation if found.
5371 """
5372 return self.findAndParseMacroInvocationEx(sCode, sMacro)[0];
5373
5374 def findAndParseFirstMacroInvocation(self, sCode, asMacro):
5375 """
5376 Returns same as findAndParseMacroInvocation.
5377 """
5378 for sMacro in asMacro:
5379 asRet = self.findAndParseMacroInvocation(sCode, sMacro);
5380 if asRet is not None:
5381 return asRet;
5382 return None;
5383
5384 def workerIemOpMnemonicEx(self, sMacro, sStats, sAsm, sForm, sUpper, sLower, # pylint: disable=too-many-arguments
5385 sDisHints, sIemHints, asOperands):
5386 """
5387 Processes one of the a IEMOP_MNEMONIC0EX, IEMOP_MNEMONIC1EX, IEMOP_MNEMONIC2EX,
5388 IEMOP_MNEMONIC3EX, and IEMOP_MNEMONIC4EX macros.
5389 """
5390 #
5391 # Some invocation checks.
5392 #
5393 if sUpper != sUpper.upper():
5394 self.error('%s: bad a_Upper parameter: %s' % (sMacro, sUpper,));
5395 if sLower != sLower.lower():
5396 self.error('%s: bad a_Lower parameter: %s' % (sMacro, sLower,));
5397 if sUpper.lower() != sLower:
5398 self.error('%s: a_Upper and a_Lower parameters does not match: %s vs %s' % (sMacro, sUpper, sLower,));
5399 if not self.oReMnemonic.match(sLower):
5400 self.error('%s: invalid a_Lower: %s (valid: %s)' % (sMacro, sLower, self.oReMnemonic.pattern,));
5401
5402 #
5403 # Check if sIemHints tells us to not consider this macro invocation.
5404 #
5405 if sIemHints.find('IEMOPHINT_SKIP_PYTHON') >= 0:
5406 return True;
5407
5408 # Apply to the last instruction only for now.
5409 if not self.aoCurInstrs:
5410 self.addInstruction();
5411 oInstr = self.aoCurInstrs[-1];
5412 if oInstr.iLineMnemonicMacro == -1:
5413 oInstr.iLineMnemonicMacro = self.iLine;
5414 else:
5415 self.error('%s: already saw a IEMOP_MNEMONIC* macro on line %u for this instruction'
5416 % (sMacro, oInstr.iLineMnemonicMacro,));
5417
5418 # Mnemonic
5419 if oInstr.sMnemonic is None:
5420 oInstr.sMnemonic = sLower;
5421 elif oInstr.sMnemonic != sLower:
5422 self.error('%s: current instruction and a_Lower does not match: %s vs %s' % (sMacro, oInstr.sMnemonic, sLower,));
5423
5424 # Process operands.
5425 if len(oInstr.aoOperands) not in [0, len(asOperands)]:
5426 self.error('%s: number of operands given by @opN does not match macro: %s vs %s'
5427 % (sMacro, len(oInstr.aoOperands), len(asOperands),));
5428 for iOperand, sType in enumerate(asOperands):
5429 sWhere = g_kdOpTypes.get(sType, [None, None])[1];
5430 if sWhere is None:
5431 self.error('%s: unknown a_Op%u value: %s' % (sMacro, iOperand + 1, sType));
5432 if iOperand < len(oInstr.aoOperands): # error recovery.
5433 sWhere = oInstr.aoOperands[iOperand].sWhere;
5434 sType = oInstr.aoOperands[iOperand].sType;
5435 else:
5436 sWhere = 'reg';
5437 sType = 'Gb';
5438 if iOperand == len(oInstr.aoOperands):
5439 oInstr.aoOperands.append(Operand(sWhere, sType))
5440 elif oInstr.aoOperands[iOperand].sWhere != sWhere or oInstr.aoOperands[iOperand].sType != sType:
5441 self.error('%s: @op%u and a_Op%u mismatch: %s:%s vs %s:%s'
5442 % (sMacro, iOperand + 1, iOperand + 1, oInstr.aoOperands[iOperand].sWhere,
5443 oInstr.aoOperands[iOperand].sType, sWhere, sType,));
5444
5445 # Encoding.
5446 if sForm not in g_kdIemForms:
5447 self.error('%s: unknown a_Form value: %s' % (sMacro, sForm,));
5448 else:
5449 if oInstr.sEncoding is None:
5450 oInstr.sEncoding = g_kdIemForms[sForm][0];
5451 elif g_kdIemForms[sForm][0] != oInstr.sEncoding:
5452 self.error('%s: current instruction @openc and a_Form does not match: %s vs %s (%s)'
5453 % (sMacro, oInstr.sEncoding, g_kdIemForms[sForm], sForm));
5454
5455 # Check the parameter locations for the encoding.
5456 if g_kdIemForms[sForm][1] is not None:
5457 if len(g_kdIemForms[sForm][1]) > len(oInstr.aoOperands):
5458 self.error('%s: The a_Form=%s has a different operand count: %s (form) vs %s'
5459 % (sMacro, sForm, len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands) ));
5460 else:
5461 for iOperand, sWhere in enumerate(g_kdIemForms[sForm][1]):
5462 if oInstr.aoOperands[iOperand].sWhere != sWhere:
5463 self.error('%s: current instruction @op%u and a_Form location does not match: %s vs %s (%s)'
5464 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sWhere, sWhere, sForm,));
5465 sOpFormMatch = g_kdOpTypes[oInstr.aoOperands[iOperand].sType][4];
5466 if (sOpFormMatch in [ 'REG', 'MEM', ] and sForm.find('_' + sOpFormMatch) < 0) \
5467 or (sOpFormMatch in [ 'FIXED', ] and sForm.find(sOpFormMatch) < 0) \
5468 or (sOpFormMatch == 'RM' and (sForm.find('_MEM') > 0 or sForm.find('_REG') > 0) ) \
5469 or (sOpFormMatch == 'V' and ( not (sForm.find('VEX') > 0 or sForm.find('XOP')) \
5470 or sForm.replace('VEX','').find('V') < 0) ):
5471 self.error('%s: current instruction @op%u and a_Form type does not match: %s/%s vs %s'
5472 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sType, sOpFormMatch, sForm, ));
5473 if len(g_kdIemForms[sForm][1]) < len(oInstr.aoOperands):
5474 for iOperand in range(len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands)):
5475 if oInstr.aoOperands[iOperand].sType != 'FIXED' \
5476 and g_kdOpTypes[oInstr.aoOperands[iOperand].sType][0] != 'IDX_ParseFixedReg':
5477 self.error('%s: Expected FIXED type operand #%u following operands given by a_Form=%s: %s (%s)'
5478 % (sMacro, iOperand, sForm, oInstr.aoOperands[iOperand].sType,
5479 oInstr.aoOperands[iOperand].sWhere));
5480
5481
5482 # Check @opcodesub
5483 if oInstr.sSubOpcode \
5484 and g_kdIemForms[sForm][2] \
5485 and oInstr.sSubOpcode.find(g_kdIemForms[sForm][2]) < 0:
5486 self.error('%s: current instruction @opcodesub and a_Form does not match: %s vs %s (%s)'
5487 % (sMacro, oInstr.sSubOpcode, g_kdIemForms[sForm][2], sForm,));
5488
5489 # Stats.
5490 if not self.oReStatsName.match(sStats):
5491 self.error('%s: invalid a_Stats value: %s' % (sMacro, sStats,));
5492 elif oInstr.sStats is None:
5493 oInstr.sStats = sStats;
5494 elif oInstr.sStats != sStats:
5495 self.error('%s: mismatching @opstats and a_Stats value: %s vs %s'
5496 % (sMacro, oInstr.sStats, sStats,));
5497
5498 # Process the hints (simply merge with @ophints w/o checking anything).
5499 for sHint in sDisHints.split('|'):
5500 sHint = sHint.strip();
5501 if sHint.startswith('DISOPTYPE_'):
5502 sShortHint = sHint[len('DISOPTYPE_'):].lower();
5503 if sShortHint in g_kdHints:
5504 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5505 else:
5506 self.error('%s: unknown a_fDisHints value: %s' % (sMacro, sHint,));
5507 elif sHint != '0':
5508 self.error('%s: expected a_fDisHints value: %s' % (sMacro, sHint,));
5509
5510 for sHint in sIemHints.split('|'):
5511 sHint = sHint.strip();
5512 if sHint.startswith('IEMOPHINT_'):
5513 sShortHint = sHint[len('IEMOPHINT_'):].lower();
5514 if sShortHint in g_kdHints:
5515 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5516 else:
5517 self.error('%s: unknown a_fIemHints value: %s' % (sMacro, sHint,));
5518 elif sHint != '0':
5519 self.error('%s: expected a_fIemHints value: %s' % (sMacro, sHint,));
5520
5521 _ = sAsm;
5522 return True;
5523
5524 def workerIemOpMnemonic(self, sMacro, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands):
5525 """
5526 Processes one of the a IEMOP_MNEMONIC0, IEMOP_MNEMONIC1, IEMOP_MNEMONIC2,
5527 IEMOP_MNEMONIC3, and IEMOP_MNEMONIC4 macros.
5528 """
5529 if not asOperands:
5530 return self.workerIemOpMnemonicEx(sMacro, sLower, sLower, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5531 return self.workerIemOpMnemonicEx(sMacro, sLower + '_' + '_'.join(asOperands), sLower + ' ' + ','.join(asOperands),
5532 sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5533
5534 def workerIemMcBegin(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine):
5535 """
5536 Process a IEM_MC_BEGIN macro invocation.
5537 """
5538 if self.fDebugMc:
5539 self.debug('IEM_MC_BEGIN on %s off %s' % (self.iLine, offBeginStatementInLine,));
5540 #self.debug('%s<eos>' % (sCode,));
5541
5542 # Check preconditions.
5543 if not self.oCurFunction:
5544 self.raiseError('IEM_MC_BEGIN w/o current function (%s)' % (sCode,));
5545 if self.oCurMcBlock:
5546 self.raiseError('IEM_MC_BEGIN before IEM_MC_END. Previous IEM_MC_BEGIN at line %u' % (self.oCurMcBlock.iBeginLine,));
5547
5548 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5549 cchIndent = offBeginStatementInCodeStr;
5550 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5551 if offPrevNewline >= 0:
5552 cchIndent -= offPrevNewline + 1;
5553 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5554
5555 # Start a new block.
5556 # But don't add it to the list unless the context matches the host architecture.
5557 self.oCurMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine, self.oCurFunction, self.iMcBlockInFunc,
5558 oInstruction = self.aoCurInstrs[-1] if self.aoCurInstrs else None,
5559 cchIndent = cchIndent);
5560 try:
5561 if ( not self.aoCppCondStack
5562 or not self.sHostArch
5563 or self.PreprocessorConditional.isInBlockForArch(self.aoCppCondStack, self.sHostArch, self.iLine)):
5564 g_aoMcBlocks.append(self.oCurMcBlock);
5565 self.cTotalMcBlocks += 1;
5566 except Exception as oXcpt:
5567 self.raiseError(oXcpt.args[0]);
5568
5569 if self.oCurMcBlock.oInstruction:
5570 self.oCurMcBlock.oInstruction.aoMcBlocks.append(self.oCurMcBlock);
5571 self.iMcBlockInFunc += 1;
5572 return True;
5573
5574 @staticmethod
5575 def extractLinesFromMacroExpansionLine(sRawLine, offBegin, offEnd, sBeginStmt = 'IEM_MC_BEGIN'):
5576 """
5577 Helper used by workerIemMcEnd and workerIemMcDeferToCImplXRet for
5578 extracting a statement block from a string that's the result of macro
5579 expansion and therefore contains multiple "sub-lines" as it were.
5580
5581 Returns list of lines covering offBegin thru offEnd in sRawLine.
5582 """
5583
5584 off = sRawLine.find('\n', offEnd);
5585 if off > 0:
5586 sRawLine = sRawLine[:off + 1];
5587
5588 off = sRawLine.rfind('\n', 0, offBegin) + 1;
5589 sRawLine = sRawLine[off:];
5590 if not sRawLine.strip().startswith(sBeginStmt):
5591 sRawLine = sRawLine[offBegin - off:]
5592
5593 return [sLine + '\n' for sLine in sRawLine.split('\n')];
5594
5595 def workerIemMcEnd(self, offEndStatementInLine):
5596 """
5597 Process a IEM_MC_END macro invocation.
5598 """
5599 if self.fDebugMc:
5600 self.debug('IEM_MC_END on %s off %s' % (self.iLine, offEndStatementInLine,));
5601
5602 # Check preconditions.
5603 if not self.oCurMcBlock:
5604 self.raiseError('IEM_MC_END w/o IEM_MC_BEGIN.');
5605
5606 #
5607 # HACK ALERT! For blocks originating from macro expansion the start and
5608 # end line will be the same, but the line has multiple
5609 # newlines inside it. So, we have to do some extra tricks
5610 # to get the lines out of there. We ASSUME macros aren't
5611 # messy, but keep IEM_MC_BEGIN/END on separate lines.
5612 #
5613 if self.iLine > self.oCurMcBlock.iBeginLine:
5614 asLines = self.asLines[self.oCurMcBlock.iBeginLine - 1 : self.iLine];
5615 if not asLines[0].strip().startswith('IEM_MC_BEGIN'):
5616 self.raiseError('IEM_MC_BEGIN is not the first word on the line');
5617
5618 # Hack alert! Detect mixed tail/head macros a la cmpxchg16b and split up the lines
5619 # so we can deal correctly with IEM_MC_END below and everything else.
5620 for sLine in asLines:
5621 cNewLines = sLine.count('\n');
5622 assert cNewLines > 0;
5623 if cNewLines > 1:
5624 asLines = self.extractLinesFromMacroExpansionLine(''.join(asLines),
5625 self.oCurMcBlock.offBeginLine,
5626 offEndStatementInLine
5627 + sum(len(s) for s in asLines)
5628 - len(asLines[-1]));
5629 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Partial;
5630 break;
5631 else:
5632 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Entire;
5633 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1],
5634 self.oCurMcBlock.offBeginLine, offEndStatementInLine);
5635
5636 #
5637 # Strip anything following the IEM_MC_END(); statement in the final line,
5638 # so that we don't carry on any trailing 'break' after macro expansions
5639 # like for iemOp_movsb_Xb_Yb.
5640 #
5641 while asLines[-1].strip() == '':
5642 asLines.pop();
5643 sFinal = asLines[-1];
5644 offFinalEnd = sFinal.find('IEM_MC_END');
5645 offEndInFinal = offFinalEnd;
5646 if offFinalEnd < 0: self.raiseError('bogus IEM_MC_END: Not in final line: %s' % (sFinal,));
5647 offFinalEnd += len('IEM_MC_END');
5648
5649 while sFinal[offFinalEnd].isspace():
5650 offFinalEnd += 1;
5651 if sFinal[offFinalEnd] != '(': self.raiseError('bogus IEM_MC_END: Expected "(" at %s: %s' % (offFinalEnd, sFinal,));
5652 offFinalEnd += 1;
5653
5654 while sFinal[offFinalEnd].isspace():
5655 offFinalEnd += 1;
5656 if sFinal[offFinalEnd] != ')': self.raiseError('bogus IEM_MC_END: Expected ")" at %s: %s' % (offFinalEnd, sFinal,));
5657 offFinalEnd += 1;
5658
5659 while sFinal[offFinalEnd].isspace():
5660 offFinalEnd += 1;
5661 if sFinal[offFinalEnd] != ';': self.raiseError('bogus IEM_MC_END: Expected ";" at %s: %s' % (offFinalEnd, sFinal,));
5662 offFinalEnd += 1;
5663
5664 asLines[-1] = sFinal[: offFinalEnd];
5665
5666 #
5667 # Complete and discard the current block.
5668 #
5669 self.oCurMcBlock.complete(self.iLine, offEndStatementInLine,
5670 offEndStatementInLine + offFinalEnd - offEndInFinal, asLines);
5671 self.oCurMcBlock = None;
5672 return True;
5673
5674 def workerIemMcDeferToCImplXRet(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine, cParams):
5675 """
5676 Process a IEM_MC_DEFER_TO_CIMPL_[1-5]_RET macro invocation.
5677 """
5678 sStmt = 'IEM_MC_DEFER_TO_CIMPL_%d_RET' % (cParams,);
5679 if self.fDebugMc:
5680 self.debug('%s on %s off %s' % (sStmt, self.iLine, offBeginStatementInLine,));
5681 #self.debug('%s<eos>' % (sCode,));
5682
5683 # Check preconditions.
5684 if not self.oCurFunction:
5685 self.raiseError('%s w/o current function (%s)' % (sStmt, sCode,));
5686 if self.oCurMcBlock:
5687 self.raiseError('%s inside IEM_MC_BEGIN block starting at line %u' % (sStmt, self.oCurMcBlock.iBeginLine,));
5688
5689 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5690 cchIndent = offBeginStatementInCodeStr;
5691 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5692 if offPrevNewline >= 0:
5693 cchIndent -= offPrevNewline + 1;
5694 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5695
5696 # Start a new block.
5697 oMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine, self.oCurFunction, self.iMcBlockInFunc,
5698 oInstruction = self.aoCurInstrs[-1] if self.aoCurInstrs else None,
5699 cchIndent = cchIndent, fDeferToCImpl = True);
5700
5701 # Parse the statment.
5702 asArgs, offAfter, cLines = self.findAndParseMacroInvocationEx(sCode, sStmt, offBeginStatementInCodeStr);
5703 if asArgs is None:
5704 self.raiseError('%s: Closing parenthesis not found!' % (sStmt,));
5705 if len(asArgs) != cParams + 4:
5706 self.raiseError('%s: findAndParseMacroInvocationEx returns %s args, expected %s! (%s)'
5707 % (sStmt, len(asArgs), cParams + 4, asArgs));
5708
5709 oMcBlock.aoStmts = [ McBlock.parseMcDeferToCImpl(oMcBlock, asArgs[0], asArgs[1:]), ];
5710
5711 # These MCs are not typically part of macro expansions, but let's get
5712 # it out of the way immediately if it's the case.
5713 if cLines > 0 or self.asLines[oMcBlock.iBeginLine - 1].count('\n') <= 1:
5714 asLines = self.asLines[self.iLine - 1 : self.iLine - 1 + cLines + 1];
5715 assert offAfter < len(asLines[-1]) and asLines[-1][offAfter] == ';', \
5716 'iBeginLine=%d iLine=%d offAfter=%s line: "%s"' % (oMcBlock.iBeginLine, self.iLine, offAfter, asLines[-1],);
5717 asLines[-1] = asLines[-1][:offAfter + 1];
5718 else:
5719 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1], offBeginStatementInCodeStr,
5720 offAfter, sStmt);
5721 assert asLines[-1].find(';') >= 0;
5722 asLines[-1] = asLines[-1][:asLines[-1].find(';') + 1];
5723
5724 assert asLines[0].find(sStmt) >= 0;
5725 #if not asLines[0].strip().startswith(sStmt):
5726 # self.raiseError('%s is not the first word on the line: %s' % (sStmt, asLines[0].strip()));
5727
5728 # Advance to the line with the closing ')'.
5729 self.iLine += cLines;
5730
5731 # Complete the block.
5732 oMcBlock.complete(self.iLine, 0 if cLines > 0 else offBeginStatementInCodeStr, offAfter + 1, asLines);
5733
5734 g_aoMcBlocks.append(oMcBlock);
5735 if oMcBlock.oInstruction:
5736 oMcBlock.oInstruction.aoMcBlocks.append(oMcBlock);
5737 self.cTotalMcBlocks += 1;
5738 self.iMcBlockInFunc += 1;
5739
5740 return True;
5741
5742 def workerStartFunction(self, asArgs):
5743 """
5744 Deals with the start of a decoder function.
5745
5746 These are all defined using one of the FNIEMOP*_DEF* and FNIEMOP_*STUB*
5747 macros, so we get a argument list for these where the 0th argument is the
5748 macro name.
5749 """
5750 # Complete any existing function.
5751 if self.oCurFunction:
5752 self.oCurFunction.complete(self.iLine - 1, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine - 1]);
5753
5754 # Create the new function.
5755 self.oCurFunction = DecoderFunction(self.sSrcFile, self.iLine, asArgs[1], asArgs);
5756 return True;
5757
5758 def checkCodeForMacro(self, sCode, offLine):
5759 """
5760 Checks code for relevant macro invocation.
5761 """
5762
5763 #
5764 # Scan macro invocations.
5765 #
5766 if sCode.find('(') > 0:
5767 # Look for instruction decoder function definitions. ASSUME single line.
5768 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5769 [ 'FNIEMOP_DEF',
5770 'FNIEMOPRM_DEF',
5771 'FNIEMOP_STUB',
5772 'FNIEMOP_STUB_1',
5773 'FNIEMOP_UD_STUB',
5774 'FNIEMOP_UD_STUB_1' ]);
5775 if asArgs is not None:
5776 self.workerStartFunction(asArgs);
5777 #self.debug('%s: oCurFunction=%s' % (self.iLine, self.oCurFunction.sName,));
5778
5779 if not self.aoCurInstrs:
5780 self.addInstruction();
5781 for oInstr in self.aoCurInstrs:
5782 if oInstr.iLineFnIemOpMacro == -1:
5783 oInstr.iLineFnIemOpMacro = self.iLine;
5784 else:
5785 self.error('%s: already seen a FNIEMOP_XXX macro for %s' % (asArgs[0], oInstr,) );
5786 self.setInstrunctionAttrib('sFunction', asArgs[1]);
5787 self.setInstrunctionAttrib('fStub', asArgs[0].find('STUB') > 0, fOverwrite = True);
5788 self.setInstrunctionAttrib('fUdStub', asArgs[0].find('UD_STUB') > 0, fOverwrite = True);
5789 if asArgs[0].find('STUB') > 0:
5790 self.doneInstructions(fEndOfFunction = True);
5791 return True;
5792
5793 # Check for worker function definitions, so we can get a context for MC blocks.
5794 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5795 [ 'FNIEMOP_DEF_1',
5796 'FNIEMOP_DEF_2', ]);
5797 if asArgs is not None:
5798 self.workerStartFunction(asArgs);
5799 #self.debug('%s: oCurFunction=%s (%s)' % (self.iLine, self.oCurFunction.sName, asArgs[0]));
5800 return True;
5801
5802 # IEMOP_HLP_DONE_VEX_DECODING_*
5803 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5804 [ 'IEMOP_HLP_DONE_VEX_DECODING',
5805 'IEMOP_HLP_DONE_VEX_DECODING_L0',
5806 'IEMOP_HLP_DONE_VEX_DECODING_NO_VVVV',
5807 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV',
5808 ]);
5809 if asArgs is not None:
5810 sMacro = asArgs[0];
5811 if sMacro in ('IEMOP_HLP_DONE_VEX_DECODING_L0', 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV', ):
5812 for oInstr in self.aoCurInstrs:
5813 if 'vex_l_zero' not in oInstr.dHints:
5814 if oInstr.iLineMnemonicMacro >= 0:
5815 self.errorOnLine(oInstr.iLineMnemonicMacro,
5816 'Missing IEMOPHINT_VEX_L_ZERO! (%s on line %d)' % (sMacro, self.iLine,));
5817 oInstr.dHints['vex_l_zero'] = True;
5818
5819 #
5820 # IEMOP_MNEMONIC*
5821 #
5822 if sCode.find('IEMOP_MNEMONIC') >= 0:
5823 # IEMOP_MNEMONIC(a_Stats, a_szMnemonic) IEMOP_INC_STATS(a_Stats)
5824 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC');
5825 if asArgs is not None:
5826 if len(self.aoCurInstrs) == 1:
5827 oInstr = self.aoCurInstrs[0];
5828 if oInstr.sStats is None:
5829 oInstr.sStats = asArgs[1];
5830 self.deriveMnemonicAndOperandsFromStats(oInstr, asArgs[1]);
5831
5832 # IEMOP_MNEMONIC0EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5833 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0EX');
5834 if asArgs is not None:
5835 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[6],
5836 asArgs[7], []);
5837 # IEMOP_MNEMONIC1EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5838 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1EX');
5839 if asArgs is not None:
5840 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[7],
5841 asArgs[8], [asArgs[6],]);
5842 # IEMOP_MNEMONIC2EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5843 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2EX');
5844 if asArgs is not None:
5845 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[8],
5846 asArgs[9], [asArgs[6], asArgs[7]]);
5847 # IEMOP_MNEMONIC3EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints,
5848 # a_fIemHints)
5849 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3EX');
5850 if asArgs is not None:
5851 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[9],
5852 asArgs[10], [asArgs[6], asArgs[7], asArgs[8],]);
5853 # IEMOP_MNEMONIC4EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints,
5854 # a_fIemHints)
5855 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4EX');
5856 if asArgs is not None:
5857 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[10],
5858 asArgs[11], [asArgs[6], asArgs[7], asArgs[8], asArgs[9],]);
5859
5860 # IEMOP_MNEMONIC0(a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5861 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0');
5862 if asArgs is not None:
5863 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], []);
5864 # IEMOP_MNEMONIC1(a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5865 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1');
5866 if asArgs is not None:
5867 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[5], asArgs[6], [asArgs[4],]);
5868 # IEMOP_MNEMONIC2(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5869 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2');
5870 if asArgs is not None:
5871 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[6], asArgs[7],
5872 [asArgs[4], asArgs[5],]);
5873 # IEMOP_MNEMONIC3(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints, a_fIemHints)
5874 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3');
5875 if asArgs is not None:
5876 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[7], asArgs[8],
5877 [asArgs[4], asArgs[5], asArgs[6],]);
5878 # IEMOP_MNEMONIC4(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints, a_fIemHints)
5879 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4');
5880 if asArgs is not None:
5881 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[8], asArgs[9],
5882 [asArgs[4], asArgs[5], asArgs[6], asArgs[7],]);
5883
5884 #
5885 # IEM_MC_BEGIN + IEM_MC_END.
5886 # We must support multiple instances per code snippet.
5887 #
5888 offCode = sCode.find('IEM_MC_');
5889 if offCode >= 0:
5890 for oMatch in self.oReMcBeginEnd.finditer(sCode, offCode):
5891 if oMatch.group(1) == 'END':
5892 self.workerIemMcEnd(offLine + oMatch.start());
5893 elif oMatch.group(1) == 'BEGIN':
5894 self.workerIemMcBegin(sCode, oMatch.start(), offLine + oMatch.start());
5895 else:
5896 self.workerIemMcDeferToCImplXRet(sCode, oMatch.start(), offLine + oMatch.start(),
5897 int(oMatch.group(1)[len('DEFER_TO_CIMPL_')]));
5898 return True;
5899
5900 return False;
5901
5902 def workerPreprocessorRecreateMacroRegex(self):
5903 """
5904 Recreates self.oReMacros when self.dMacros changes.
5905 """
5906 if self.dMacros:
5907 sRegex = '';
5908 for sName, oMacro in self.dMacros.items():
5909 if sRegex:
5910 sRegex += r'|' + sName;
5911 else:
5912 sRegex = r'\b(' + sName;
5913 if oMacro.asArgs is not None:
5914 sRegex += r'\s*\(';
5915 else:
5916 sRegex += r'\b';
5917 sRegex += ')';
5918 self.oReMacros = re.compile(sRegex);
5919 else:
5920 self.oReMacros = None;
5921 return True;
5922
5923 def workerPreprocessorDefine(self, sRest):
5924 """
5925 Handles a macro #define, the sRest is what follows after the directive word.
5926 """
5927 assert sRest[-1] == '\n';
5928
5929 #
5930 # If using line continutation, just concat all the lines together,
5931 # preserving the newline character but not the escaping.
5932 #
5933 iLineStart = self.iLine;
5934 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
5935 sRest = sRest[0:-2].rstrip() + '\n' + self.asLines[self.iLine];
5936 self.iLine += 1;
5937 #self.debug('workerPreprocessorDefine: sRest=%s<EOS>' % (sRest,));
5938
5939 #
5940 # Use regex to split out the name, argument list and body.
5941 # If this fails, we assume it's a simple macro.
5942 #
5943 oMatch = self.oReHashDefine2.match(sRest);
5944 if oMatch:
5945 sAllArgs = oMatch.group(2).strip();
5946 asArgs = [sParam.strip() for sParam in sAllArgs.split(',')] if sAllArgs else None;
5947 sBody = oMatch.group(3);
5948 else:
5949 oMatch = self.oReHashDefine3.match(sRest);
5950 if not oMatch:
5951 self.debug('workerPreprocessorDefine: wtf? sRest=%s' % (sRest,));
5952 return self.error('bogus macro definition: %s' % (sRest,));
5953 asArgs = None;
5954 sBody = oMatch.group(2);
5955 sName = oMatch.group(1);
5956 assert sName == sName.strip();
5957 #self.debug('workerPreprocessorDefine: sName=%s asArgs=%s sBody=%s<EOS>' % (sName, asArgs, sBody));
5958
5959 #
5960 # Is this of any interest to us? We do NOT support MC blocks wihtin
5961 # nested macro expansion, just to avoid lots of extra work.
5962 #
5963 # There is only limited support for macros expanding to partial MC blocks.
5964 #
5965 # Note! IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX and other macros someone making
5966 # use of IEMOP_RAISE_INVALID_LOCK_PREFIX_RET() will be ignored here and
5967 # dealt with by overriding IEMOP_RAISE_INVALID_LOCK_PREFIX_RET and its
5968 # siblings in the recompiler. This is a lot simpler than nested macro
5969 # expansion and lots of heuristics for locating all the relevant macros.
5970 # Also, this way we don't produce lots of unnecessary threaded functions.
5971 #
5972 if sBody.find("IEM_MC_BEGIN") < 0 and sBody.find("IEM_MC_END") < 0:
5973 #self.debug('workerPreprocessorDefine: irrelevant (%s: %s)' % (sName, sBody));
5974 return True;
5975
5976 #
5977 # Add the macro.
5978 #
5979 if self.fDebugPreproc:
5980 self.debug('#define %s on line %u' % (sName, self.iLine,));
5981 self.dMacros[sName] = SimpleParser.Macro(sName, asArgs, sBody.strip(), iLineStart);
5982 return self.workerPreprocessorRecreateMacroRegex();
5983
5984 def workerPreprocessorUndef(self, sRest):
5985 """
5986 Handles a macro #undef, the sRest is what follows after the directive word.
5987 """
5988 # Quick comment strip and isolate the name.
5989 offSlash = sRest.find('/');
5990 if offSlash > 0:
5991 sRest = sRest[:offSlash];
5992 sName = sRest.strip();
5993
5994 # Remove the macro if we're clocking it.
5995 if sName in self.dMacros:
5996 if self.fDebugPreproc:
5997 self.debug('#undef %s on line %u' % (sName, self.iLine,));
5998 del self.dMacros[sName];
5999 return self.workerPreprocessorRecreateMacroRegex();
6000
6001 return True;
6002
6003 def workerPreprocessorIfOrElif(self, sDirective, sRest):
6004 """
6005 Handles an #if, #ifdef, #ifndef or #elif directive.
6006 """
6007 #
6008 # Sanity check #elif.
6009 #
6010 if sDirective == 'elif':
6011 if len(self.aoCppCondStack) == 0:
6012 self.raiseError('#elif without #if');
6013 if self.aoCppCondStack[-1].fInElse:
6014 self.raiseError('#elif after #else');
6015
6016 #
6017 # If using line continutation, just concat all the lines together,
6018 # stripping both the newline and escape characters.
6019 #
6020 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
6021 sRest = sRest[0:-2].rstrip() + ' ' + self.asLines[self.iLine];
6022 self.iLine += 1;
6023
6024 # Strip it of all comments and leading and trailing blanks.
6025 sRest = self.stripComments(sRest).strip();
6026
6027 #
6028 # Stash it.
6029 #
6030 try:
6031 oPreprocCond = self.PreprocessorConditional(sDirective, sRest);
6032 except Exception as oXcpt:
6033 self.raiseError(oXcpt.args[0]);
6034
6035 if sDirective == 'elif':
6036 self.aoCppCondStack[-1].aoElif.append(oPreprocCond);
6037 else:
6038 self.aoCppCondStack.append(oPreprocCond);
6039
6040 return True;
6041
6042 def workerPreprocessorElse(self):
6043 """
6044 Handles an #else directive.
6045 """
6046 if len(self.aoCppCondStack) == 0:
6047 self.raiseError('#else without #if');
6048 if self.aoCppCondStack[-1].fInElse:
6049 self.raiseError('Another #else after #else');
6050
6051 self.aoCppCondStack[-1].fInElse = True;
6052 return True;
6053
6054 def workerPreprocessorEndif(self):
6055 """
6056 Handles an #endif directive.
6057 """
6058 if len(self.aoCppCondStack) == 0:
6059 self.raiseError('#endif without #if');
6060
6061 self.aoCppCondStack.pop();
6062 return True;
6063
6064 def checkPreprocessorDirective(self, sLine):
6065 """
6066 Handles a preprocessor directive.
6067 """
6068 # Skip past the preprocessor hash.
6069 off = sLine.find('#');
6070 assert off >= 0;
6071 off += 1;
6072 while off < len(sLine) and sLine[off].isspace():
6073 off += 1;
6074
6075 # Extract the directive.
6076 offDirective = off;
6077 while off < len(sLine) and not sLine[off].isspace():
6078 off += 1;
6079 sDirective = sLine[offDirective:off];
6080 if self.fDebugPreproc:
6081 self.debug('line %d: #%s...' % (self.iLine, sDirective));
6082
6083 # Skip spaces following it to where the arguments/whatever starts.
6084 while off + 1 < len(sLine) and sLine[off + 1].isspace():
6085 off += 1;
6086 sTail = sLine[off:];
6087
6088 # Handle the directive.
6089 if sDirective == 'define':
6090 return self.workerPreprocessorDefine(sTail);
6091 if sDirective == 'undef':
6092 return self.workerPreprocessorUndef(sTail);
6093 if sDirective in ('if', 'ifdef', 'ifndef', 'elif',):
6094 return self.workerPreprocessorIfOrElif(sDirective, sTail);
6095 if sDirective == 'else':
6096 return self.workerPreprocessorElse();
6097 if sDirective == 'endif':
6098 return self.workerPreprocessorEndif();
6099
6100 if self.fDebugPreproc:
6101 self.debug('line %d: Unknown preprocessor directive: %s' % (self.iLine, sDirective));
6102 return False;
6103
6104 def expandMacros(self, sLine, oMatch):
6105 """
6106 Expands macros we know about in the given line.
6107 Currently we ASSUME there is only one and that is what oMatch matched.
6108 """
6109 #
6110 # Get our bearings.
6111 #
6112 offMatch = oMatch.start();
6113 sName = oMatch.group(1);
6114 assert sName == sLine[oMatch.start() : oMatch.end()];
6115 fWithArgs = sName.endswith('(');
6116 if fWithArgs:
6117 sName = sName[:-1].strip();
6118 oMacro = self.dMacros[sName] # type: SimpleParser.Macro
6119
6120 #
6121 # Deal with simple macro invocations w/o parameters.
6122 #
6123 if not fWithArgs:
6124 if self.fDebugPreproc:
6125 self.debug('expanding simple macro %s on line %u' % (sName, self.iLine,));
6126 return sLine[:offMatch] + oMacro.expandMacro(self) + sLine[oMatch.end():];
6127
6128 #
6129 # Complicated macro with parameters.
6130 # Start by extracting the parameters. ASSUMES they are all on the same line!
6131 #
6132 cLevel = 1;
6133 offCur = oMatch.end();
6134 offCurArg = offCur;
6135 asArgs = [];
6136 while True:
6137 if offCur >= len(sLine):
6138 self.raiseError('expandMacros: Invocation of macro %s spans multiple lines!' % (sName,));
6139 ch = sLine[offCur];
6140 if ch == '(':
6141 cLevel += 1;
6142 elif ch == ')':
6143 cLevel -= 1;
6144 if cLevel == 0:
6145 asArgs.append(sLine[offCurArg:offCur].strip());
6146 break;
6147 elif ch == ',' and cLevel == 1:
6148 asArgs.append(sLine[offCurArg:offCur].strip());
6149 offCurArg = offCur + 1;
6150 offCur += 1;
6151 if len(oMacro.asArgs) == 0 and len(asArgs) == 1 and asArgs[0] == '': # trick for empty parameter list.
6152 asArgs = [];
6153 if len(oMacro.asArgs) != len(asArgs):
6154 self.raiseError('expandMacros: Argument mismatch in %s invocation' % (oMacro.sName,));
6155
6156 #
6157 # Do the expanding.
6158 #
6159 if self.fDebugPreproc:
6160 self.debug('expanding macro %s on line %u with arguments %s' % (sName, self.iLine, asArgs));
6161 return sLine[:offMatch] + oMacro.expandMacro(self, asArgs) + sLine[offCur + 1 :];
6162
6163 def parse(self):
6164 """
6165 Parses the given file.
6166
6167 Returns number or errors.
6168 Raises exception on fatal trouble.
6169 """
6170 #self.debug('Parsing %s' % (self.sSrcFile,));
6171
6172 #
6173 # Loop thru the lines.
6174 #
6175 # Please mind that self.iLine may be updated by checkCodeForMacro and
6176 # other worker methods.
6177 #
6178 while self.iLine < len(self.asLines):
6179 sLine = self.asLines[self.iLine];
6180 self.iLine += 1;
6181 #self.debug('line %u: %s' % (self.iLine, sLine[:-1]));
6182
6183 # Expand macros we know about if we're currently in code.
6184 if self.iState == self.kiCode and self.oReMacros:
6185 oMatch = self.oReMacros.search(sLine);
6186 if oMatch:
6187 sLine = self.expandMacros(sLine, oMatch);
6188 if self.fDebugPreproc:
6189 self.debug('line %d: expanded\n%s ==>\n%s' % (self.iLine, self.asLines[self.iLine - 1], sLine[:-1],));
6190 self.asLines[self.iLine - 1] = sLine;
6191
6192 # Check for preprocessor directives before comments and other stuff.
6193 # ASSUMES preprocessor directives doesn't end with multiline comments.
6194 if self.iState == self.kiCode and sLine.lstrip().startswith('#'):
6195 if self.fDebugPreproc:
6196 self.debug('line %d: preproc' % (self.iLine,));
6197 self.checkPreprocessorDirective(sLine);
6198 else:
6199 # Look for comments.
6200 offSlash = sLine.find('/');
6201 if offSlash >= 0:
6202 if offSlash + 1 >= len(sLine) or sLine[offSlash + 1] != '/' or self.iState != self.kiCode:
6203 offLine = 0;
6204 while offLine < len(sLine):
6205 if self.iState == self.kiCode:
6206 # Look for substantial multiline comment so we pass the following MC as a whole line:
6207 # IEM_MC_ARG_CONST(uint8_t, bImmArg, /*=*/ bImm, 2);
6208 # Note! We ignore C++ comments here, assuming these aren't used in lines with C-style comments.
6209 offHit = sLine.find('/*', offLine);
6210 while offHit >= 0:
6211 offEnd = sLine.find('*/', offHit + 2);
6212 if offEnd < 0 or offEnd - offHit >= 16: # 16 chars is a bit random.
6213 break;
6214 offHit = sLine.find('/*', offEnd);
6215
6216 if offHit >= 0:
6217 self.checkCodeForMacro(sLine[offLine:offHit], offLine);
6218 self.sComment = '';
6219 self.iCommentLine = self.iLine;
6220 self.iState = self.kiCommentMulti;
6221 offLine = offHit + 2;
6222 else:
6223 self.checkCodeForMacro(sLine[offLine:], offLine);
6224 offLine = len(sLine);
6225
6226 elif self.iState == self.kiCommentMulti:
6227 offHit = sLine.find('*/', offLine);
6228 if offHit >= 0:
6229 self.sComment += sLine[offLine:offHit];
6230 self.iState = self.kiCode;
6231 offLine = offHit + 2;
6232 self.parseComment();
6233 else:
6234 self.sComment += sLine[offLine:];
6235 offLine = len(sLine);
6236 else:
6237 assert False;
6238 # C++ line comment.
6239 elif offSlash > 0:
6240 self.checkCodeForMacro(sLine[:offSlash], 0);
6241
6242 # No slash, but append the line if in multi-line comment.
6243 elif self.iState == self.kiCommentMulti:
6244 #self.debug('line %d: multi' % (self.iLine,));
6245 self.sComment += sLine;
6246
6247 # No slash, but check code line for relevant macro.
6248 elif ( self.iState == self.kiCode
6249 and (sLine.find('IEMOP_') >= 0 or sLine.find('FNIEMOPRM_DEF') >= 0 or sLine.find('IEM_MC') >= 0)):
6250 #self.debug('line %d: macro' % (self.iLine,));
6251 self.checkCodeForMacro(sLine, 0);
6252
6253 # If the line is a '}' in the first position, complete the instructions.
6254 elif self.iState == self.kiCode and sLine[0] == '}':
6255 #self.debug('line %d: }' % (self.iLine,));
6256 self.doneInstructions(fEndOfFunction = True);
6257
6258 # Look for instruction table on the form 'IEM_STATIC const PFNIEMOP g_apfnVexMap3'
6259 # so we can check/add @oppfx info from it.
6260 elif self.iState == self.kiCode and sLine.find('PFNIEMOP') > 0 and self.oReFunTable.match(sLine):
6261 self.parseFunctionTable(sLine);
6262
6263 self.doneInstructions(fEndOfFunction = True);
6264 self.debug('%3s%% / %3s stubs out of %4s instructions and %4s MC blocks in %s'
6265 % (self.cTotalStubs * 100 // max(self.cTotalInstr, 1), self.cTotalStubs, self.cTotalInstr,
6266 self.cTotalMcBlocks, os.path.basename(self.sSrcFile),));
6267 return self.printErrors();
6268
6269# Some sanity checking.
6270def __sanityCheckEFlagsClasses():
6271 for sClass, dLists in SimpleParser.kdEFlagsClasses.items():
6272 for sAttrib, asFlags in dLists.items():
6273 for sFlag in asFlags:
6274 assert sFlag in g_kdEFlagsMnemonics, 'sClass=%s sAttrib=%s sFlag=%s' % (sClass, sAttrib, sFlag,);
6275__sanityCheckEFlagsClasses();
6276
6277## The parsed content of IEMAllInstCommonBodyMacros.h.
6278g_oParsedCommonBodyMacros = None # type: SimpleParser
6279
6280def __parseFileByName(sSrcFile, sDefaultMap, sHostArch):
6281 """
6282 Parses one source file for instruction specfications.
6283 """
6284 #
6285 # Read sSrcFile into a line array.
6286 #
6287 try:
6288 oFile = open(sSrcFile, "r"); # pylint: disable=consider-using-with,unspecified-encoding
6289 except Exception as oXcpt:
6290 raise Exception("failed to open %s for reading: %s" % (sSrcFile, oXcpt,));
6291 try:
6292 asLines = oFile.readlines();
6293 except Exception as oXcpt:
6294 raise Exception("failed to read %s: %s" % (sSrcFile, oXcpt,));
6295 finally:
6296 oFile.close();
6297
6298 #
6299 # On the first call, we parse IEMAllInstCommonBodyMacros.h so we
6300 # can use the macros from it when processing the other files.
6301 #
6302 global g_oParsedCommonBodyMacros;
6303 if g_oParsedCommonBodyMacros is None:
6304 # Locate the file.
6305 sCommonBodyMacros = os.path.join(os.path.split(sSrcFile)[0], 'IEMAllInstCommonBodyMacros.h');
6306 if not os.path.isfile(sCommonBodyMacros):
6307 sCommonBodyMacros = os.path.join(os.path.split(__file__)[0], 'IEMAllInstCommonBodyMacros.h');
6308
6309 # Read it.
6310 try:
6311 with open(sCommonBodyMacros, "r") as oIncFile: # pylint: disable=unspecified-encoding
6312 asIncFiles = oIncFile.readlines();
6313 except Exception as oXcpt:
6314 raise Exception("failed to open/read %s: %s" % (sCommonBodyMacros, oXcpt,));
6315
6316 # Parse it.
6317 try:
6318 oParser = SimpleParser(sCommonBodyMacros, asIncFiles, 'one', sHostArch);
6319 if oParser.parse() != 0:
6320 raise ParserException('%s: errors: See above' % (sCommonBodyMacros, ));
6321 if oParser.cTotalInstr != 0 or oParser.cTotalStubs != 0 or oParser.cTotalTagged != 0 or oParser.cTotalMcBlocks != 0:
6322 raise ParserException('%s: error: Unexpectedly found %u instr, %u tags, %u stubs and %u MCs, expecting zero. %s'
6323 % (sCommonBodyMacros, oParser.cTotalInstr, oParser.cTotalStubs, oParser.cTotalTagged,
6324 oParser.cTotalMcBlocks,
6325 ', '.join(sorted( [str(oMcBlock.iBeginLine) for oMcBlock in g_aoMcBlocks]
6326 + [str(oInstr.iLineCreated) for oInstr in g_aoAllInstructions])),));
6327 except ParserException as oXcpt:
6328 print(str(oXcpt), file = sys.stderr);
6329 raise;
6330 g_oParsedCommonBodyMacros = oParser;
6331
6332 #
6333 # Do the parsing.
6334 #
6335 try:
6336 oParser = SimpleParser(sSrcFile, asLines, sDefaultMap, sHostArch, g_oParsedCommonBodyMacros);
6337 return (oParser.parse(), oParser) ;
6338 except ParserException as oXcpt:
6339 print(str(oXcpt), file = sys.stderr);
6340 raise;
6341
6342
6343def __doTestCopying():
6344 """
6345 Executes the asCopyTests instructions.
6346 """
6347 asErrors = [];
6348 for oDstInstr in g_aoAllInstructions:
6349 if oDstInstr.asCopyTests:
6350 for sSrcInstr in oDstInstr.asCopyTests:
6351 oSrcInstr = g_dAllInstructionsByStat.get(sSrcInstr, None);
6352 if oSrcInstr:
6353 aoSrcInstrs = [oSrcInstr,];
6354 else:
6355 aoSrcInstrs = g_dAllInstructionsByFunction.get(sSrcInstr, []);
6356 if aoSrcInstrs:
6357 for oSrcInstr in aoSrcInstrs:
6358 if oSrcInstr != oDstInstr:
6359 oDstInstr.aoTests.extend(oSrcInstr.aoTests);
6360 else:
6361 asErrors.append('%s:%s: error: @opcopytests reference "%s" matches the destination\n'
6362 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
6363 else:
6364 asErrors.append('%s:%s: error: @opcopytests reference "%s" not found\n'
6365 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
6366
6367 if asErrors:
6368 sys.stderr.write(u''.join(asErrors));
6369 return len(asErrors);
6370
6371
6372def __applyOnlyTest():
6373 """
6374 If g_aoOnlyTestInstructions contains any instructions, drop aoTests from
6375 all other instructions so that only these get tested.
6376 """
6377 if g_aoOnlyTestInstructions:
6378 for oInstr in g_aoAllInstructions:
6379 if oInstr.aoTests:
6380 if oInstr not in g_aoOnlyTestInstructions:
6381 oInstr.aoTests = [];
6382 return 0;
6383
6384## List of all main instruction files, their default maps and file sets (-1 means included it all sets).
6385g_aaoAllInstrFilesAndDefaultMapAndSet = (
6386 ( 'IEMAllInstCommon.cpp.h', 'one', -1, ),
6387 ( 'IEMAllInstOneByte.cpp.h', 'one', 1, ),
6388 ( 'IEMAllInst3DNow.cpp.h', '3dnow', 2, ),
6389 ( 'IEMAllInstTwoByte0f.cpp.h', 'two0f', 2, ),
6390 ( 'IEMAllInstThree0f38.cpp.h', 'three0f38', 3, ),
6391 ( 'IEMAllInstThree0f3a.cpp.h', 'three0f3a', 3, ),
6392 ( 'IEMAllInstVexMap1.cpp.h', 'vexmap1', 4, ),
6393 ( 'IEMAllInstVexMap2.cpp.h', 'vexmap2', 4, ),
6394 ( 'IEMAllInstVexMap3.cpp.h', 'vexmap3', 4, ),
6395);
6396
6397def __parseFilesWorker(asFilesAndDefaultMap, sHostArch):
6398 """
6399 Parses all the IEMAllInstruction*.cpp.h files.
6400
6401 Returns a list of the parsers on success.
6402 Raises exception on failure.
6403 """
6404 sSrcDir = os.path.dirname(os.path.abspath(__file__));
6405 cErrors = 0;
6406 aoParsers = [];
6407 for sFilename, sDefaultMap in asFilesAndDefaultMap:
6408 if not os.path.split(sFilename)[0] and not os.path.exists(sFilename):
6409 sFilename = os.path.join(sSrcDir, sFilename);
6410 cThisErrors, oParser = __parseFileByName(sFilename, sDefaultMap, sHostArch);
6411 cErrors += cThisErrors;
6412 aoParsers.append(oParser);
6413 cErrors += __doTestCopying();
6414 cErrors += __applyOnlyTest();
6415
6416 # Total stub stats:
6417 cTotalStubs = 0;
6418 for oInstr in g_aoAllInstructions:
6419 cTotalStubs += oInstr.fStub;
6420 print('debug: %3s%% / %3s stubs out of %4s instructions and %4s MC blocks in total'
6421 % (cTotalStubs * 100 // len(g_aoAllInstructions), cTotalStubs, len(g_aoAllInstructions), len(g_aoMcBlocks),),
6422 file = sys.stderr);
6423
6424 if cErrors != 0:
6425 raise Exception('%d parse errors' % (cErrors,));
6426 return aoParsers;
6427
6428
6429def parseFiles(asFiles, sHostArch = None):
6430 """
6431 Parses a selection of IEMAllInstruction*.cpp.h files.
6432
6433 Returns a list of the parsers on success.
6434 Raises exception on failure.
6435 """
6436 # Look up default maps for the files and call __parseFilesWorker to do the job.
6437 asFilesAndDefaultMap = [];
6438 for sFilename in asFiles:
6439 sName = os.path.split(sFilename)[1].lower();
6440 sMap = None;
6441 for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet:
6442 if aoInfo[0].lower() == sName:
6443 sMap = aoInfo[1];
6444 break;
6445 if not sMap:
6446 raise Exception('Unable to classify file: %s' % (sFilename,));
6447 asFilesAndDefaultMap.append((sFilename, sMap));
6448
6449 return __parseFilesWorker(asFilesAndDefaultMap, sHostArch);
6450
6451
6452def parseAll(sHostArch = None):
6453 """
6454 Parses all the IEMAllInstruction*.cpp.h files.
6455
6456 Returns a list of the parsers on success.
6457 Raises exception on failure.
6458 """
6459 return __parseFilesWorker([aoInfo[0:2] for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet], sHostArch);
6460
6461
6462#
6463# Generators (may perhaps move later).
6464#
6465def __formatDisassemblerTableEntry(oInstr):
6466 """
6467 """
6468 sMacro = 'OP';
6469 cMaxOperands = 3;
6470 if len(oInstr.aoOperands) > 3:
6471 sMacro = 'OPVEX'
6472 cMaxOperands = 4;
6473 assert len(oInstr.aoOperands) <= cMaxOperands;
6474
6475 #
6476 # Format string.
6477 #
6478 sTmp = '%s("%s' % (sMacro, oInstr.sMnemonic,);
6479 for iOperand, oOperand in enumerate(oInstr.aoOperands):
6480 sTmp += ' ' if iOperand == 0 else ',';
6481 if g_kdOpTypes[oOperand.sType][2][0] != '%': ## @todo remove upper() later.
6482 sTmp += g_kdOpTypes[oOperand.sType][2].upper(); ## @todo remove upper() later.
6483 else:
6484 sTmp += g_kdOpTypes[oOperand.sType][2];
6485 sTmp += '",';
6486 asColumns = [ sTmp, ];
6487
6488 #
6489 # Decoders.
6490 #
6491 iStart = len(asColumns);
6492 if oInstr.sEncoding is None:
6493 pass;
6494 elif oInstr.sEncoding == 'ModR/M':
6495 # ASSUME the first operand is using the ModR/M encoding
6496 assert len(oInstr.aoOperands) >= 1 and oInstr.aoOperands[0].usesModRM(), "oInstr=%s" % (oInstr,);
6497 asColumns.append('IDX_ParseModRM,');
6498 elif oInstr.sEncoding in [ 'prefix', ]:
6499 for oOperand in oInstr.aoOperands:
6500 asColumns.append('0,');
6501 elif oInstr.sEncoding in [ 'fixed', 'VEX.fixed' ]:
6502 pass;
6503 elif oInstr.sEncoding == 'VEX.ModR/M':
6504 asColumns.append('IDX_ParseModRM,');
6505 elif oInstr.sEncoding == 'vex2':
6506 asColumns.append('IDX_ParseVex2b,')
6507 elif oInstr.sEncoding == 'vex3':
6508 asColumns.append('IDX_ParseVex3b,')
6509 elif oInstr.sEncoding in g_dInstructionMaps:
6510 asColumns.append(g_dInstructionMaps[oInstr.sEncoding].sDisParse + ',');
6511 else:
6512 ## @todo
6513 #IDX_ParseTwoByteEsc,
6514 #IDX_ParseGrp1,
6515 #IDX_ParseShiftGrp2,
6516 #IDX_ParseGrp3,
6517 #IDX_ParseGrp4,
6518 #IDX_ParseGrp5,
6519 #IDX_Parse3DNow,
6520 #IDX_ParseGrp6,
6521 #IDX_ParseGrp7,
6522 #IDX_ParseGrp8,
6523 #IDX_ParseGrp9,
6524 #IDX_ParseGrp10,
6525 #IDX_ParseGrp12,
6526 #IDX_ParseGrp13,
6527 #IDX_ParseGrp14,
6528 #IDX_ParseGrp15,
6529 #IDX_ParseGrp16,
6530 #IDX_ParseThreeByteEsc4,
6531 #IDX_ParseThreeByteEsc5,
6532 #IDX_ParseModFence,
6533 #IDX_ParseEscFP,
6534 #IDX_ParseNopPause,
6535 #IDX_ParseInvOpModRM,
6536 assert False, str(oInstr);
6537
6538 # Check for immediates and stuff in the remaining operands.
6539 for oOperand in oInstr.aoOperands[len(asColumns) - iStart:]:
6540 sIdx = g_kdOpTypes[oOperand.sType][0];
6541 #if sIdx != 'IDX_UseModRM':
6542 asColumns.append(sIdx + ',');
6543 asColumns.extend(['0,'] * (cMaxOperands - (len(asColumns) - iStart)));
6544
6545 #
6546 # Opcode and operands.
6547 #
6548 assert oInstr.sDisEnum, str(oInstr);
6549 asColumns.append(oInstr.sDisEnum + ',');
6550 iStart = len(asColumns)
6551 for oOperand in oInstr.aoOperands:
6552 asColumns.append('OP_PARM_' + g_kdOpTypes[oOperand.sType][3] + ',');
6553 asColumns.extend(['OP_PARM_NONE,'] * (cMaxOperands - (len(asColumns) - iStart)));
6554
6555 #
6556 # Flags.
6557 #
6558 sTmp = '';
6559 for sHint in sorted(oInstr.dHints.keys()):
6560 sDefine = g_kdHints[sHint];
6561 if sDefine.startswith('DISOPTYPE_'):
6562 if sTmp:
6563 sTmp += ' | ' + sDefine;
6564 else:
6565 sTmp += sDefine;
6566 if sTmp:
6567 sTmp += '),';
6568 else:
6569 sTmp += '0),';
6570 asColumns.append(sTmp);
6571
6572 #
6573 # Format the columns into a line.
6574 #
6575 aoffColumns = [4, 29, 49, 65, 77, 89, 109, 125, 141, 157, 183, 199];
6576 sLine = '';
6577 for i, s in enumerate(asColumns):
6578 if len(sLine) < aoffColumns[i]:
6579 sLine += ' ' * (aoffColumns[i] - len(sLine));
6580 else:
6581 sLine += ' ';
6582 sLine += s;
6583
6584 # OP("psrlw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE,
6585 # DISOPTYPE_HARMLESS),
6586 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
6587 # { pszOpcode, idxParse1, idxParse2, idxParse3, 0, opcode, param1, param2, param3, 0, 0, optype }
6588 return sLine;
6589
6590def __checkIfShortTable(aoTableOrdered, oMap):
6591 """
6592 Returns (iInstr, cInstructions, fShortTable)
6593 """
6594
6595 # Determin how much we can trim off.
6596 cInstructions = len(aoTableOrdered);
6597 while cInstructions > 0 and aoTableOrdered[cInstructions - 1] is None:
6598 cInstructions -= 1;
6599
6600 iInstr = 0;
6601 while iInstr < cInstructions and aoTableOrdered[iInstr] is None:
6602 iInstr += 1;
6603
6604 # If we can save more than 30%, we go for the short table version.
6605 if iInstr + len(aoTableOrdered) - cInstructions >= len(aoTableOrdered) // 30:
6606 return (iInstr, cInstructions, True);
6607 _ = oMap; # Use this for overriding.
6608
6609 # Output the full table.
6610 return (0, len(aoTableOrdered), False);
6611
6612def generateDisassemblerTables(oDstFile = sys.stdout):
6613 """
6614 Generates disassembler tables.
6615
6616 Returns exit code.
6617 """
6618
6619 #
6620 # Parse all.
6621 #
6622 try:
6623 parseAll();
6624 except Exception as oXcpt:
6625 print('error: parseAll failed: %s' % (oXcpt,), file = sys.stderr);
6626 traceback.print_exc(file = sys.stderr);
6627 return 1;
6628
6629
6630 #
6631 # The disassembler uses a slightly different table layout to save space,
6632 # since several of the prefix varia
6633 #
6634 aoDisasmMaps = [];
6635 for sName, oMap in sorted(iter(g_dInstructionMaps.items()),
6636 key = lambda aKV: aKV[1].sEncoding + ''.join(aKV[1].asLeadOpcodes)):
6637 if oMap.sSelector != 'byte+pfx':
6638 aoDisasmMaps.append(oMap);
6639 else:
6640 # Split the map by prefix.
6641 aoDisasmMaps.append(oMap.copy(oMap.sName, 'none'));
6642 aoDisasmMaps.append(oMap.copy(oMap.sName + '_66', '0x66'));
6643 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F3', '0xf3'));
6644 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F2', '0xf2'));
6645
6646 #
6647 # Dump each map.
6648 #
6649 asHeaderLines = [];
6650 print("debug: maps=%s\n" % (', '.join([oMap.sName for oMap in aoDisasmMaps]),), file = sys.stderr);
6651 for oMap in aoDisasmMaps:
6652 sName = oMap.sName;
6653
6654 if not sName.startswith("vex"): continue; # only looking at the vex maps at the moment.
6655
6656 #
6657 # Get the instructions for the map and see if we can do a short version or not.
6658 #
6659 aoTableOrder = oMap.getInstructionsInTableOrder();
6660 cEntriesPerByte = oMap.getEntriesPerByte();
6661 (iInstrStart, iInstrEnd, fShortTable) = __checkIfShortTable(aoTableOrder, oMap);
6662
6663 #
6664 # Output the table start.
6665 # Note! Short tables are static and only accessible via the map range record.
6666 #
6667 asLines = [];
6668 asLines.append('/* Generated from: %-11s Selector: %-7s Encoding: %-7s Lead bytes opcodes: %s */'
6669 % ( oMap.sName, oMap.sSelector, oMap.sEncoding, ' '.join(oMap.asLeadOpcodes), ));
6670 if fShortTable:
6671 asLines.append('%sconst DISOPCODE %s[] =' % ('static ' if fShortTable else '', oMap.getDisasTableName(),));
6672 else:
6673 asHeaderLines.append('extern const DISOPCODE %s[%d];' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6674 asLines.append( 'const DISOPCODE %s[%d] =' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6675 asLines.append('{');
6676
6677 if fShortTable and (iInstrStart & ((0x10 * cEntriesPerByte) - 1)) != 0:
6678 asLines.append(' /* %#04x: */' % (iInstrStart,));
6679
6680 #
6681 # Output the instructions.
6682 #
6683 iInstr = iInstrStart;
6684 while iInstr < iInstrEnd:
6685 oInstr = aoTableOrder[iInstr];
6686 if (iInstr & ((0x10 * cEntriesPerByte) - 1)) == 0:
6687 if iInstr != iInstrStart:
6688 asLines.append('');
6689 asLines.append(' /* %x */' % ((iInstr // cEntriesPerByte) >> 4,));
6690
6691 if oInstr is None:
6692 # Invalid. Optimize blocks of invalid instructions.
6693 cInvalidInstrs = 1;
6694 while iInstr + cInvalidInstrs < len(aoTableOrder) and aoTableOrder[iInstr + cInvalidInstrs] is None:
6695 cInvalidInstrs += 1;
6696 if (iInstr & (0x10 * cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= 0x10 * cEntriesPerByte:
6697 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (0x10 * cEntriesPerByte,));
6698 iInstr += 0x10 * cEntriesPerByte - 1;
6699 elif cEntriesPerByte > 1:
6700 if (iInstr & (cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= cEntriesPerByte:
6701 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (cEntriesPerByte,));
6702 iInstr += 3;
6703 else:
6704 asLines.append(' /* %#04x/%d */ INVALID_OPCODE,'
6705 % (iInstr // cEntriesPerByte, iInstr % cEntriesPerByte));
6706 else:
6707 asLines.append(' /* %#04x */ INVALID_OPCODE,' % (iInstr));
6708 elif isinstance(oInstr, list):
6709 if len(oInstr) != 0:
6710 asLines.append(' /* %#04x */ ComplicatedListStuffNeedingWrapper, /* \n -- %s */'
6711 % (iInstr, '\n -- '.join([str(oItem) for oItem in oInstr]),));
6712 else:
6713 asLines.append(__formatDisassemblerTableEntry(oInstr));
6714 else:
6715 asLines.append(__formatDisassemblerTableEntry(oInstr));
6716
6717 iInstr += 1;
6718
6719 if iInstrStart >= iInstrEnd:
6720 asLines.append(' /* dummy */ INVALID_OPCODE');
6721
6722 asLines.append('};');
6723 asLines.append('AssertCompile(RT_ELEMENTS(%s) == %s);' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6724
6725 #
6726 # We always emit a map range record, assuming the linker will eliminate the unnecessary ones.
6727 #
6728 asHeaderLines.append('extern const DISOPMAPDESC %sRange;' % (oMap.getDisasRangeName()));
6729 asLines.append('const DISOPMAPDESC %s = { &%s[0], %#04x, RT_ELEMENTS(%s) };'
6730 % (oMap.getDisasRangeName(), oMap.getDisasTableName(), iInstrStart, oMap.getDisasTableName(),));
6731
6732 #
6733 # Write out the lines.
6734 #
6735 oDstFile.write('\n'.join(asLines));
6736 oDstFile.write('\n');
6737 oDstFile.write('\n');
6738 #break; #for now
6739 return 0;
6740
6741if __name__ == '__main__':
6742 sys.exit(generateDisassemblerTables());
6743
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette