VirtualBox

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

Last change on this file since 106432 was 106181, checked in by vboxsync, 2 months ago

VMM/IEM: Check that IEM_MC_REF_EFLAGS is used correctly and won't cause trouble for EFLAGS calculation postponing. bugref:10720

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 332.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllInstPython.py 106181 2024-09-30 15:24:34Z 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: 106181 $"
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_U32_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3168 'IEM_MC_FETCH_MEM_XMM_U64_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3169 'IEM_MC_FETCH_MEM_YMM': (McBlock.parseMcGeneric, True, True, False, ),
3170 'IEM_MC_FETCH_MEM_YMM_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, False, ),
3171 'IEM_MC_FETCH_MEM_YMM_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3172 'IEM_MC_FETCH_MEM_YMM_ALIGN_AVX_AND_YREG_YMM': (McBlock.parseMcGeneric, True, True, False, ),
3173 'IEM_MC_FETCH_MEM16_U8': (McBlock.parseMcGeneric, True, True, False, ),
3174 'IEM_MC_FETCH_MEM32_U8': (McBlock.parseMcGeneric, True, True, False, ),
3175 'IEM_MC_FETCH_MREG_U8': (McBlock.parseMcGeneric, False, False, False, ),
3176 'IEM_MC_FETCH_MREG_U16': (McBlock.parseMcGeneric, False, False, False, ),
3177 'IEM_MC_FETCH_MREG_U32': (McBlock.parseMcGeneric, False, False, False, ),
3178 'IEM_MC_FETCH_MREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
3179 'IEM_MC_FETCH_SREG_BASE_U32': (McBlock.parseMcGeneric, False, False, False, ),
3180 'IEM_MC_FETCH_SREG_BASE_U64': (McBlock.parseMcGeneric, False, False, False, ),
3181 'IEM_MC_FETCH_SREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
3182 'IEM_MC_FETCH_SREG_ZX_U32': (McBlock.parseMcGeneric, False, False, True, ),
3183 'IEM_MC_FETCH_SREG_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
3184 'IEM_MC_FETCH_XREG_R32': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3185 'IEM_MC_FETCH_XREG_R64': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3186 'IEM_MC_FETCH_XREG_U128': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3187 'IEM_MC_FETCH_XREG_U16': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3188 'IEM_MC_FETCH_XREG_U32': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3189 'IEM_MC_FETCH_XREG_U64': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3190 'IEM_MC_FETCH_XREG_U8': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3191 'IEM_MC_FETCH_XREG_XMM': (McBlock.parseMcGeneric, False, False, False, ),
3192 'IEM_MC_FETCH_XREG_PAIR_U128': (McBlock.parseMcGeneric, False, False, False, ),
3193 'IEM_MC_FETCH_XREG_PAIR_U128_AND_RAX_RDX_U64': (McBlock.parseMcGeneric, False, False, False, ),
3194 'IEM_MC_FETCH_XREG_PAIR_U128_AND_EAX_EDX_U32_SX_U64': (McBlock.parseMcGeneric, False, False, False, ),
3195 'IEM_MC_FETCH_XREG_PAIR_XMM': (McBlock.parseMcGeneric, False, False, False, ),
3196 'IEM_MC_FETCH_YREG_U128': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3197 'IEM_MC_FETCH_YREG_U256': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3198 'IEM_MC_FETCH_YREG_YMM': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3199 'IEM_MC_FETCH_YREG_U32': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3200 'IEM_MC_FETCH_YREG_U64': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3201 'IEM_MC_FETCH_YREG_PAIR_YMM': (McBlock.parseMcGeneric, False, False, False, ),
3202 'IEM_MC_FLIP_EFL_BIT': (McBlock.parseMcGeneric, True, True, True, ),
3203 'IEM_MC_FPU_FROM_MMX_MODE': (McBlock.parseMcGeneric, True, True, False, ),
3204 'IEM_MC_FPU_STACK_DEC_TOP': (McBlock.parseMcGeneric, True, True, False, ),
3205 'IEM_MC_FPU_STACK_FREE': (McBlock.parseMcGeneric, True, True, False, ),
3206 'IEM_MC_FPU_STACK_INC_TOP': (McBlock.parseMcGeneric, True, True, False, ),
3207 'IEM_MC_FPU_STACK_PUSH_OVERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
3208 'IEM_MC_FPU_STACK_PUSH_OVERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3209 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
3210 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW_TWO': (McBlock.parseMcGeneric, True, True, False, ),
3211 'IEM_MC_FPU_STACK_UNDERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
3212 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3213 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3214 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3215 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP_POP': (McBlock.parseMcGeneric, True, True, False, ),
3216 'IEM_MC_FPU_TO_MMX_MODE': (McBlock.parseMcGeneric, True, True, False, ),
3217 'IEM_MC_HINT_FLUSH_GUEST_SHADOW': (McBlock.parseMcGeneric, True, True, True, ),
3218 'IEM_MC_IF_CX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
3219 'IEM_MC_IF_CX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
3220 'IEM_MC_IF_CX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3221 'IEM_MC_IF_CX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3222 'IEM_MC_IF_ECX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
3223 'IEM_MC_IF_ECX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
3224 'IEM_MC_IF_ECX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3225 'IEM_MC_IF_ECX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3226 'IEM_MC_IF_EFL_ANY_BITS_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3227 'IEM_MC_IF_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3228 'IEM_MC_IF_EFL_BIT_NOT_SET_AND_BITS_EQ': (McBlock.parseMcGenericCond, True, False, True, ),
3229 'IEM_MC_IF_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3230 'IEM_MC_IF_EFL_BIT_SET_OR_BITS_NE': (McBlock.parseMcGenericCond, True, False, True, ),
3231 'IEM_MC_IF_EFL_BITS_EQ': (McBlock.parseMcGenericCond, True, False, True, ),
3232 'IEM_MC_IF_EFL_BITS_NE': (McBlock.parseMcGenericCond, True, False, True, ),
3233 'IEM_MC_IF_EFL_NO_BITS_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3234 'IEM_MC_IF_FCW_IM': (McBlock.parseMcGenericCond, True, True, False, ),
3235 'IEM_MC_IF_FPUREG_IS_EMPTY': (McBlock.parseMcGenericCond, True, True, False, ),
3236 'IEM_MC_IF_FPUREG_NOT_EMPTY': (McBlock.parseMcGenericCond, True, True, False, ),
3237 'IEM_MC_IF_FPUREG_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, True, False, ),
3238 'IEM_MC_IF_GREG_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3239 'IEM_MC_IF_LOCAL_IS_Z': (McBlock.parseMcGenericCond, True, False, True, ),
3240 'IEM_MC_IF_RCX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
3241 'IEM_MC_IF_RCX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
3242 'IEM_MC_IF_RCX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3243 'IEM_MC_IF_RCX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3244 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, True, False, ),
3245 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80_FIRST': (McBlock.parseMcGenericCond, True, True, False, ),
3246 'IEM_MC_IND_CALL_U16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3247 'IEM_MC_IND_CALL_U32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3248 'IEM_MC_IND_CALL_U64_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3249 'IEM_MC_INT_CLEAR_ZMM_256_UP': (McBlock.parseMcGeneric, True, True, False, ),
3250 'IEM_MC_LIVENESS_GREG_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3251 'IEM_MC_LIVENESS_GREG_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3252 'IEM_MC_LIVENESS_GREG_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3253 'IEM_MC_LIVENESS_MREG_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3254 'IEM_MC_LIVENESS_MREG_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3255 'IEM_MC_LIVENESS_MREG_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3256 'IEM_MC_LIVENESS_XREG_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3257 'IEM_MC_LIVENESS_XREG_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3258 'IEM_MC_LIVENESS_XREG_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3259 'IEM_MC_LIVENESS_MXCSR_INPUT': (McBlock.parseMcGeneric, False, False, True, ),
3260 'IEM_MC_LIVENESS_MXCSR_CLOBBER': (McBlock.parseMcGeneric, False, False, True, ),
3261 'IEM_MC_LIVENESS_MXCSR_MODIFY': (McBlock.parseMcGeneric, False, False, True, ),
3262 'IEM_MC_LOCAL': (McBlock.parseMcLocal, False, False, True, ),
3263 'IEM_MC_LOCAL_ASSIGN': (McBlock.parseMcLocalAssign, False, False, True, ),
3264 'IEM_MC_LOCAL_CONST': (McBlock.parseMcLocalConst, False, False, True, ),
3265 'IEM_MC_LOCAL_EFLAGS': (McBlock.parseMcLocalEFlags, True, True, True, ),
3266 'IEM_MC_NOREF': (McBlock.parseMcGeneric, False, False, True, ),
3267 'IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, True, ),
3268 'IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, True, True, ),
3269 'IEM_MC_MAYBE_RAISE_FPU_XCPT': (McBlock.parseMcGeneric, True, True, True, ),
3270 'IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3271 'IEM_MC_MAYBE_RAISE_MMX_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3272 'IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0': (McBlock.parseMcGeneric, True, True, False, ),
3273 'IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, True, ),
3274 'IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, True, True, ),
3275 'IEM_MC_MEM_COMMIT_AND_UNMAP_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3276 'IEM_MC_MEM_COMMIT_AND_UNMAP_RW': (McBlock.parseMcGeneric, True, True, True, ),
3277 'IEM_MC_MEM_COMMIT_AND_UNMAP_RO': (McBlock.parseMcGeneric, True, True, True, ),
3278 'IEM_MC_MEM_COMMIT_AND_UNMAP_WO': (McBlock.parseMcGeneric, True, True, True, ),
3279 'IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE_WO': (McBlock.parseMcGeneric, True, True, False, ),
3280 'IEM_MC_MEM_MAP_D80_WO': (McBlock.parseMcGeneric, True, True, True, ),
3281 'IEM_MC_MEM_MAP_I16_WO': (McBlock.parseMcGeneric, True, True, True, ),
3282 'IEM_MC_MEM_MAP_I32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3283 'IEM_MC_MEM_MAP_I64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3284 'IEM_MC_MEM_MAP_R32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3285 'IEM_MC_MEM_MAP_R64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3286 'IEM_MC_MEM_MAP_R80_WO': (McBlock.parseMcGeneric, True, True, True, ),
3287 'IEM_MC_MEM_MAP_U8_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3288 'IEM_MC_MEM_MAP_U8_RW': (McBlock.parseMcGeneric, True, True, True, ),
3289 'IEM_MC_MEM_MAP_U8_RO': (McBlock.parseMcGeneric, True, True, True, ),
3290 'IEM_MC_MEM_MAP_U8_WO': (McBlock.parseMcGeneric, True, True, True, ),
3291 'IEM_MC_MEM_MAP_U16_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3292 'IEM_MC_MEM_MAP_U16_RW': (McBlock.parseMcGeneric, True, True, True, ),
3293 'IEM_MC_MEM_MAP_U16_RO': (McBlock.parseMcGeneric, True, True, True, ),
3294 'IEM_MC_MEM_MAP_U16_WO': (McBlock.parseMcGeneric, True, True, True, ),
3295 'IEM_MC_MEM_MAP_U32_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3296 'IEM_MC_MEM_MAP_U32_RW': (McBlock.parseMcGeneric, True, True, True, ),
3297 'IEM_MC_MEM_MAP_U32_RO': (McBlock.parseMcGeneric, True, True, True, ),
3298 'IEM_MC_MEM_MAP_U32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3299 'IEM_MC_MEM_MAP_U64_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3300 'IEM_MC_MEM_MAP_U64_RW': (McBlock.parseMcGeneric, True, True, True, ),
3301 'IEM_MC_MEM_MAP_U64_RO': (McBlock.parseMcGeneric, True, True, True, ),
3302 'IEM_MC_MEM_MAP_U64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3303 'IEM_MC_MEM_MAP_U128_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3304 'IEM_MC_MEM_MAP_U128_RW': (McBlock.parseMcGeneric, True, True, True, ),
3305 'IEM_MC_MEM_MAP_U128_RO': (McBlock.parseMcGeneric, True, True, True, ),
3306 'IEM_MC_MEM_MAP_U128_WO': (McBlock.parseMcGeneric, True, True, True, ),
3307 'IEM_MC_MEM_ROLLBACK_AND_UNMAP_WO': (McBlock.parseMcGeneric, True, True, True, ),
3308 'IEM_MC_MERGE_YREG_U32_U96_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3309 'IEM_MC_MERGE_YREG_U64_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3310 'IEM_MC_MERGE_YREG_U64HI_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3311 'IEM_MC_MERGE_YREG_U64LO_U64LO_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3312 'IEM_MC_MERGE_YREG_U64LO_U64LOCAL_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3313 'IEM_MC_MERGE_YREG_U64LOCAL_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3314 'IEM_MC_MODIFIED_MREG': (McBlock.parseMcGeneric, True, True, False, ),
3315 'IEM_MC_MODIFIED_MREG_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3316 'IEM_MC_NATIVE_EMIT_0': (McBlock.parseMcGeneric, True, True, True, ),
3317 'IEM_MC_NATIVE_EMIT_1': (McBlock.parseMcGeneric, True, True, True, ),
3318 'IEM_MC_NATIVE_EMIT_2': (McBlock.parseMcGeneric, True, True, True, ),
3319 'IEM_MC_NATIVE_EMIT_2_EX': (McBlock.parseMcGeneric, True, True, True, ),
3320 'IEM_MC_NATIVE_EMIT_3': (McBlock.parseMcGeneric, True, True, True, ),
3321 'IEM_MC_NATIVE_EMIT_4': (McBlock.parseMcGeneric, True, True, True, ),
3322 'IEM_MC_NATIVE_EMIT_5': (McBlock.parseMcGeneric, True, True, True, ),
3323 'IEM_MC_NATIVE_EMIT_6': (McBlock.parseMcGeneric, True, True, True, ),
3324 'IEM_MC_NATIVE_EMIT_7': (McBlock.parseMcGeneric, True, True, True, ),
3325 'IEM_MC_NATIVE_IF': (McBlock.parseMcNativeIf, False, False, True, ),
3326 'IEM_MC_NATIVE_ELSE': (McBlock.parseMcGenericCond, False, False, True, ),
3327 'IEM_MC_NATIVE_ENDIF': (McBlock.parseMcGenericCond, False, False, True, ),
3328 'IEM_MC_NATIVE_SET_AMD64_HOST_REG_FOR_LOCAL': (McBlock.parseMcGeneric, False, False, True, ),
3329 'IEM_MC_OR_2LOCS_U32': (McBlock.parseMcGeneric, False, False, False, ),
3330 'IEM_MC_OR_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3331 'IEM_MC_OR_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3332 'IEM_MC_OR_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3333 'IEM_MC_OR_GREG_U8': (McBlock.parseMcGeneric, True, True, True, ),
3334 'IEM_MC_OR_LOCAL_U16': (McBlock.parseMcGeneric, False, False, True, ),
3335 'IEM_MC_OR_LOCAL_U32': (McBlock.parseMcGeneric, False, False, True, ),
3336 'IEM_MC_OR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, True, ),
3337 'IEM_MC_POP_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3338 'IEM_MC_POP_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3339 'IEM_MC_POP_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3340 'IEM_MC_PREPARE_AVX_USAGE': (McBlock.parseMcGeneric, False, False, True),
3341 'IEM_MC_PREPARE_FPU_USAGE': (McBlock.parseMcGeneric, False, False, True),
3342 'IEM_MC_PREPARE_SSE_USAGE': (McBlock.parseMcGeneric, False, False, True),
3343 'IEM_MC_PUSH_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3344 'IEM_MC_PUSH_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3345 'IEM_MC_PUSH_FPU_RESULT_TWO': (McBlock.parseMcGeneric, True, True, False, ),
3346 'IEM_MC_PUSH_U16': (McBlock.parseMcGeneric, True, True, True, ),
3347 'IEM_MC_PUSH_U32': (McBlock.parseMcGeneric, True, True, True, ),
3348 'IEM_MC_PUSH_U32_SREG': (McBlock.parseMcGeneric, True, True, True, ),
3349 'IEM_MC_PUSH_U64': (McBlock.parseMcGeneric, True, True, True, ),
3350 'IEM_MC_RAISE_DIVIDE_ERROR_IF_LOCAL_IS_ZERO': (McBlock.parseMcGeneric, True, True, True, ),
3351 'IEM_MC_RAISE_GP0_IF_CPL_NOT_ZERO': (McBlock.parseMcGeneric, True, True, False, ),
3352 'IEM_MC_RAISE_GP0_IF_EFF_ADDR_UNALIGNED': (McBlock.parseMcGeneric, True, True, True, ),
3353 'IEM_MC_REF_EFLAGS': (McBlock.parseMcGeneric, False, False, True, ),
3354 'IEM_MC_REF_FPUREG': (McBlock.parseMcGeneric, False, False, False, ),
3355 'IEM_MC_REF_GREG_I32': (McBlock.parseMcGeneric, False, False, True, ),
3356 'IEM_MC_REF_GREG_I32_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3357 'IEM_MC_REF_GREG_I64': (McBlock.parseMcGeneric, False, False, True, ),
3358 'IEM_MC_REF_GREG_I64_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3359 'IEM_MC_REF_GREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
3360 'IEM_MC_REF_GREG_U16_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3361 'IEM_MC_REF_GREG_U32': (McBlock.parseMcGeneric, False, False, True, ),
3362 'IEM_MC_REF_GREG_U32_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3363 'IEM_MC_REF_GREG_U64': (McBlock.parseMcGeneric, False, False, True, ),
3364 'IEM_MC_REF_GREG_U64_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3365 'IEM_MC_REF_GREG_U8': (McBlock.parseMcGeneric, False, False, False, ), # threaded
3366 'IEM_MC_REF_GREG_U8_CONST': (McBlock.parseMcGeneric, False, False, False, ), # threaded
3367 'IEM_MC_REF_MREG_U32_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3368 'IEM_MC_REF_MREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
3369 'IEM_MC_REF_MREG_U64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3370 'IEM_MC_REF_XREG_R32_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3371 'IEM_MC_REF_XREG_R64_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3372 'IEM_MC_REF_XREG_U128': (McBlock.parseMcGeneric, False, False, True, ),
3373 'IEM_MC_REF_XREG_XMM': (McBlock.parseMcGeneric, False, False, True, ),
3374 'IEM_MC_REF_XREG_U128_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3375 'IEM_MC_REF_XREG_U32_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3376 'IEM_MC_REF_XREG_U64_CONST': (McBlock.parseMcGeneric, False, False, g_fNativeSimd),
3377 'IEM_MC_REF_XREG_XMM_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3378 'IEM_MC_REF_YREG_U128': (McBlock.parseMcGeneric, False, False, False, ),
3379 'IEM_MC_REF_YREG_U128_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3380 'IEM_MC_REF_YREG_U64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3381 'IEM_MC_REL_CALL_S16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3382 'IEM_MC_REL_CALL_S32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3383 'IEM_MC_REL_CALL_S64_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3384 'IEM_MC_REL_JMP_S16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3385 'IEM_MC_REL_JMP_S32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3386 'IEM_MC_REL_JMP_S8_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3387 'IEM_MC_RETN_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3388 'IEM_MC_RETURN_ON_FAILURE': (McBlock.parseMcGeneric, False, False, False, ),
3389 'IEM_MC_SAR_LOCAL_S16': (McBlock.parseMcGeneric, False, False, True, ),
3390 'IEM_MC_SAR_LOCAL_S32': (McBlock.parseMcGeneric, False, False, True, ),
3391 'IEM_MC_SAR_LOCAL_S64': (McBlock.parseMcGeneric, False, False, True, ),
3392 'IEM_MC_SET_EFL_BIT': (McBlock.parseMcGeneric, True, True, True, ),
3393 'IEM_MC_SET_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3394 'IEM_MC_SET_RIP_U16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3395 'IEM_MC_SET_RIP_U32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3396 'IEM_MC_SET_RIP_U64_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3397 'IEM_MC_SHL_LOCAL_S16': (McBlock.parseMcGeneric, False, False, True, ),
3398 'IEM_MC_SHL_LOCAL_S32': (McBlock.parseMcGeneric, False, False, True, ),
3399 'IEM_MC_SHL_LOCAL_S64': (McBlock.parseMcGeneric, False, False, True, ),
3400 'IEM_MC_SHR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, False, ),
3401 'IEM_MC_STORE_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3402 'IEM_MC_STORE_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3403 'IEM_MC_STORE_FPU_RESULT_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3404 'IEM_MC_STORE_FPU_RESULT_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3405 'IEM_MC_STORE_FPUREG_R80_SRC_REF': (McBlock.parseMcGeneric, True, True, False, ),
3406 'IEM_MC_STORE_GREG_I32': (McBlock.parseMcGeneric, True, True, True, ),
3407 'IEM_MC_STORE_GREG_I64': (McBlock.parseMcGeneric, True, True, True, ),
3408 'IEM_MC_STORE_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3409 'IEM_MC_STORE_GREG_U16_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3410 'IEM_MC_STORE_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3411 'IEM_MC_STORE_GREG_U32_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3412 'IEM_MC_STORE_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3413 'IEM_MC_STORE_GREG_U64_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3414 'IEM_MC_STORE_GREG_U8': (McBlock.parseMcGeneric, True, True, True, ), # thrd var
3415 'IEM_MC_STORE_GREG_U8_CONST': (McBlock.parseMcGeneric, True, True, True, ), # thrd var
3416 'IEM_MC_STORE_GREG_PAIR_U32': (McBlock.parseMcGeneric, True, True, False, ),
3417 'IEM_MC_STORE_GREG_PAIR_U64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3418 'IEM_MC_STORE_MEM_I16_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3419 'IEM_MC_STORE_MEM_I32_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3420 'IEM_MC_STORE_MEM_I64_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3421 'IEM_MC_STORE_MEM_I8_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3422 'IEM_MC_STORE_MEM_INDEF_D80_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3423 'IEM_MC_STORE_MEM_NEG_QNAN_R32_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3424 'IEM_MC_STORE_MEM_NEG_QNAN_R64_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3425 'IEM_MC_STORE_MEM_NEG_QNAN_R80_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3426 'IEM_MC_STORE_MEM_U128': (McBlock.parseMcGeneric, True, True, False, ),
3427 'IEM_MC_STORE_MEM_U128_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3428 'IEM_MC_STORE_MEM_U128_ALIGN_SSE': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3429 'IEM_MC_STORE_MEM_U16': (McBlock.parseMcGeneric, True, True, True, ),
3430 'IEM_MC_STORE_MEM_U16_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3431 'IEM_MC_STORE_MEM_U256': (McBlock.parseMcGeneric, True, True, False, ),
3432 'IEM_MC_STORE_MEM_U256_NO_AC': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3433 'IEM_MC_STORE_MEM_U256_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3434 'IEM_MC_STORE_MEM_U32': (McBlock.parseMcGeneric, True, True, True, ),
3435 'IEM_MC_STORE_MEM_U32_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3436 'IEM_MC_STORE_MEM_U64': (McBlock.parseMcGeneric, True, True, True, ),
3437 'IEM_MC_STORE_MEM_U64_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3438 'IEM_MC_STORE_MEM_U8': (McBlock.parseMcGeneric, True, True, True, ),
3439 'IEM_MC_STORE_MEM_U8_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3440 'IEM_MC_STORE_MREG_U8': (McBlock.parseMcGeneric, True, True, False, ),
3441 'IEM_MC_STORE_MREG_U16': (McBlock.parseMcGeneric, True, True, False, ),
3442 'IEM_MC_STORE_MREG_U32': (McBlock.parseMcGeneric, True, True, False, ),
3443 'IEM_MC_STORE_MREG_U32_ZX_U64': (McBlock.parseMcGeneric, True, True, False, ),
3444 'IEM_MC_STORE_MREG_U64': (McBlock.parseMcGeneric, True, True, False, ),
3445 'IEM_MC_STORE_SREG_BASE_U32': (McBlock.parseMcGeneric, True, True, False, ),
3446 'IEM_MC_STORE_SREG_BASE_U64': (McBlock.parseMcGeneric, True, True, False, ),
3447 'IEM_MC_STORE_XREG_R32': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3448 'IEM_MC_STORE_XREG_R64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3449 'IEM_MC_STORE_XREG_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3450 'IEM_MC_STORE_XREG_U16': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3451 'IEM_MC_STORE_XREG_U32': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3452 'IEM_MC_STORE_XREG_U32_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3453 'IEM_MC_STORE_XREG_U32_ZX_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3454 'IEM_MC_STORE_XREG_U64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3455 'IEM_MC_STORE_XREG_U64_ZX_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3456 'IEM_MC_STORE_XREG_U8': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3457 'IEM_MC_STORE_XREG_XMM': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3458 'IEM_MC_STORE_XREG_XMM_U32': (McBlock.parseMcGeneric, True, True, False, ),
3459 'IEM_MC_STORE_XREG_XMM_U64': (McBlock.parseMcGeneric, True, True, False, ),
3460 'IEM_MC_STORE_YREG_U128': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3461 'IEM_MC_STORE_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3462 'IEM_MC_STORE_YREG_U256_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3463 'IEM_MC_STORE_YREG_YMM_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3464 'IEM_MC_STORE_YREG_U32_U256': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3465 'IEM_MC_STORE_YREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3466 'IEM_MC_STORE_YREG_U64': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3467 'IEM_MC_STORE_YREG_U64_U256': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3468 'IEM_MC_STORE_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, g_fNativeSimd),
3469 'IEM_MC_SUB_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3470 'IEM_MC_SUB_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3471 'IEM_MC_SUB_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3472 'IEM_MC_SUB_LOCAL_U16': (McBlock.parseMcGeneric, False, False, False, ),
3473 'IEM_MC_UPDATE_FPU_OPCODE_IP': (McBlock.parseMcGeneric, True, True, False, ),
3474 'IEM_MC_UPDATE_FSW': (McBlock.parseMcGeneric, True, True, False, ),
3475 'IEM_MC_UPDATE_FSW_CONST': (McBlock.parseMcGeneric, True, True, False, ),
3476 'IEM_MC_UPDATE_FSW_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3477 'IEM_MC_UPDATE_FSW_THEN_POP_POP': (McBlock.parseMcGeneric, True, True, False, ),
3478 'IEM_MC_UPDATE_FSW_WITH_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3479 'IEM_MC_UPDATE_FSW_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3480 'IEM_MC_NO_NATIVE_RECOMPILE': (McBlock.parseMcGeneric, False, False, False, ),
3481};
3482# pylint: enable=line-too-long
3483
3484## List of microcode blocks.
3485g_aoMcBlocks = [] # type: List[McBlock]
3486
3487
3488
3489class ParserException(Exception):
3490 """ Parser exception """
3491 def __init__(self, sMessage):
3492 Exception.__init__(self, sMessage);
3493
3494
3495class SimpleParser(object): # pylint: disable=too-many-instance-attributes
3496 """
3497 Parser of IEMAllInstruction*.cpp.h instruction specifications.
3498 """
3499
3500 ## @name Parser state.
3501 ## @{
3502 kiCode = 0;
3503 kiCommentMulti = 1;
3504 ## @}
3505
3506 class Macro(object):
3507 """ Macro """
3508 def __init__(self, sName, asArgs, sBody, iLine):
3509 self.sName = sName; ##< The macro name.
3510 self.asArgs = asArgs; ##< None if simple macro, list of parameters otherwise.
3511 self.sBody = sBody;
3512 self.iLine = iLine;
3513 self.oReArgMatch = re.compile(r'(\s*##\s*|\b)(' + '|'.join(asArgs) + r')(\s*##\s*|\b)') if asArgs else None;
3514
3515 @staticmethod
3516 def _needSpace(ch):
3517 """ This is just to make the expanded output a bit prettier. """
3518 return ch.isspace() and ch != '(';
3519
3520 def expandMacro(self, oParent, asArgs = None):
3521 """ Expands the macro body with the given arguments. """
3522 _ = oParent;
3523 sBody = self.sBody;
3524
3525 if self.oReArgMatch:
3526 assert len(asArgs) == len(self.asArgs);
3527 #oParent.debug('%s: %s' % (self.sName, self.oReArgMatch.pattern,));
3528
3529 dArgs = { self.asArgs[iArg]: sValue for iArg, sValue in enumerate(asArgs) };
3530 oMatch = self.oReArgMatch.search(sBody);
3531 while oMatch:
3532 sName = oMatch.group(2);
3533 #oParent.debug('%s %s..%s (%s)' % (sName, oMatch.start(), oMatch.end(),oMatch.group()));
3534 sValue = dArgs[sName];
3535 sPre = '';
3536 if not oMatch.group(1) and oMatch.start() > 0 and self._needSpace(sBody[oMatch.start()]):
3537 sPre = ' ';
3538 sPost = '';
3539 if not oMatch.group(3) and oMatch.end() < len(sBody) and self._needSpace(sBody[oMatch.end()]):
3540 sPost = ' ';
3541 sBody = sBody[ : oMatch.start()] + sPre + sValue + sPost + sBody[oMatch.end() : ];
3542 oMatch = self.oReArgMatch.search(sBody, oMatch.start() + len(sValue));
3543 else:
3544 assert not asArgs;
3545
3546 return sBody;
3547
3548 class PreprocessorConditional(object):
3549 """ Preprocessor conditional (#if/#ifdef/#ifndef/#elif/#else/#endif). """
3550
3551 ## Known defines.
3552 # - A value of 1 indicates that it's always defined.
3553 # - A value of 0 if it's always undefined
3554 # - A value of -1 if it's an arch and it depends of script parameters.
3555 # - A value of -2 if it's not recognized when filtering MC blocks.
3556 kdKnownDefines = {
3557 'IEM_WITH_ONE_BYTE_TABLE': 1,
3558 'IEM_WITH_TWO_BYTE_TABLE': 1,
3559 'IEM_WITH_THREE_0F_38': 1,
3560 'IEM_WITH_THREE_0F_3A': 1,
3561 'IEM_WITH_THREE_BYTE_TABLES': 1,
3562 'IEM_WITH_3DNOW': 1,
3563 'IEM_WITH_3DNOW_TABLE': 1,
3564 'IEM_WITH_VEX': 1,
3565 'IEM_WITH_VEX_TABLES': 1,
3566 'VBOX_WITH_NESTED_HWVIRT_VMX': 1,
3567 'VBOX_WITH_NESTED_HWVIRT_VMX_EPT': 1,
3568 'VBOX_WITH_NESTED_HWVIRT_SVM': 1,
3569 'LOG_ENABLED': 1,
3570 'RT_WITHOUT_PRAGMA_ONCE': 0,
3571 'TST_IEM_CHECK_MC': 0,
3572 'IEM_WITHOUT_ASSEMBLY': -2, ##< @todo ??
3573 'RT_ARCH_AMD64': -1,
3574 'RT_ARCH_ARM64': -1,
3575 'RT_ARCH_ARM32': -1,
3576 'RT_ARCH_X86': -1,
3577 'RT_ARCH_SPARC': -1,
3578 'RT_ARCH_SPARC64': -1,
3579 };
3580 kdBuildArchToIprt = {
3581 'amd64': 'RT_ARCH_AMD64',
3582 'arm64': 'RT_ARCH_ARM64',
3583 'sparc32': 'RT_ARCH_SPARC64',
3584 };
3585 ## For parsing the next defined(xxxx).
3586 koMatchDefined = re.compile(r'\s*defined\s*\(\s*([^ \t)]+)\s*\)\s*');
3587
3588 def __init__(self, sType, sExpr):
3589 self.sType = sType;
3590 self.sExpr = sExpr; ##< Expression without command and no leading or trailing spaces.
3591 self.aoElif = [] # type: List[PreprocessorConditional]
3592 self.fInElse = [];
3593 if sType in ('if', 'elif'):
3594 self.checkExpression(sExpr);
3595 else:
3596 self.checkSupportedDefine(sExpr)
3597
3598 @staticmethod
3599 def checkSupportedDefine(sDefine):
3600 """ Checks that sDefine is one that we support. Raises exception if unuspported. """
3601 #print('debug: checkSupportedDefine: %s' % (sDefine,), file = sys.stderr);
3602 if sDefine in SimpleParser.PreprocessorConditional.kdKnownDefines:
3603 return True;
3604 if sDefine.startswith('VMM_INCLUDED_') and sDefine.endswith('_h'):
3605 return True;
3606 raise Exception('Unsupported define: %s' % (sDefine,));
3607
3608 @staticmethod
3609 def checkExpression(sExpr):
3610 """ Check that the expression is supported. Raises exception if not. """
3611 #print('debug: checkExpression: %s' % (sExpr,), file = sys.stderr);
3612 if sExpr in ('0', '1'):
3613 return True;
3614
3615 off = 0;
3616 cParan = 0;
3617 while off < len(sExpr):
3618 ch = sExpr[off];
3619
3620 # Unary operator or parentheses:
3621 if ch in ('(', '!'):
3622 if ch == '(':
3623 cParan += 1;
3624 off += 1;
3625 else:
3626 # defined(xxxx)
3627 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3628 if oMatch:
3629 SimpleParser.PreprocessorConditional.checkSupportedDefine(oMatch.group(1));
3630 elif sExpr[off:] != '1':
3631 raise Exception('Cannot grok: \'%s\' (at %u in: \'%s\')' % (sExpr[off:10], off + 1, sExpr,));
3632 off = oMatch.end();
3633
3634 # Look for closing parentheses.
3635 while off < len(sExpr) and sExpr[off].isspace():
3636 off += 1;
3637 if cParan > 0:
3638 while off < len(sExpr) and sExpr[off] == ')':
3639 if cParan <= 0:
3640 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3641 cParan -= 1;
3642 off += 1;
3643 while off < len(sExpr) and sExpr[off].isspace():
3644 off += 1;
3645
3646 # Look for binary operator.
3647 if off >= len(sExpr):
3648 break;
3649 if sExpr[off:off + 2] in ('||', '&&'):
3650 off += 2;
3651 else:
3652 raise Exception('Cannot grok operator: \'%s\' (at %u in: \'%s\')' % (sExpr[off:2], off + 1, sExpr,));
3653
3654 # Skip spaces.
3655 while off < len(sExpr) and sExpr[off].isspace():
3656 off += 1;
3657 if cParan != 0:
3658 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3659 return True;
3660
3661 @staticmethod
3662 def isArchIncludedInExpr(sExpr, sArch):
3663 """ Checks if sArch is included in the given expression. """
3664 # We only grok defined() [|| defined()...] and [1|0] at the moment.
3665 if sExpr == '0':
3666 return False;
3667 if sExpr == '1':
3668 return True;
3669 off = 0;
3670 while off < len(sExpr):
3671 # defined(xxxx)
3672 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3673 if not oMatch:
3674 if sExpr[off:] == '1':
3675 return True;
3676 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3677 if SimpleParser.PreprocessorConditional.matchDefined(oMatch.group(1), sArch):
3678 return True;
3679 off = oMatch.end();
3680
3681 # Look for OR operator.
3682 while off + 1 < len(sExpr) and sExpr[off + 1].isspace():
3683 off += 1;
3684 if off >= len(sExpr):
3685 break;
3686 if sExpr.startswith('||'):
3687 off += 2;
3688 else:
3689 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3690
3691 return False;
3692
3693 @staticmethod
3694 def matchArch(sDefine, sArch):
3695 """ Compares sDefine (RT_ARCH_XXXX) and sArch (x86, amd64, arm64, ++). """
3696 return SimpleParser.PreprocessorConditional.kdBuildArchToIprt[sArch] == sDefine;
3697
3698 @staticmethod
3699 def matchDefined(sExpr, sArch):
3700 """ Check the result of an ifdef/ifndef expression, given sArch. """
3701 iDefine = SimpleParser.PreprocessorConditional.kdKnownDefines.get(sExpr, 0);
3702 if iDefine == -2:
3703 raise Exception('Unsupported define for MC block filtering: %s' % (sExpr,));
3704 return iDefine == 1 or (iDefine == -1 and SimpleParser.PreprocessorConditional.matchArch(sExpr, sArch));
3705
3706 def isArchIncludedInPrimaryBlock(self, sArch):
3707 """ Checks if sArch is included in the (primary) 'if' block. """
3708 if self.sType == 'ifdef':
3709 return self.matchDefined(self.sExpr, sArch);
3710 if self.sType == 'ifndef':
3711 return not self.matchDefined(self.sExpr, sArch);
3712 return self.isArchIncludedInExpr(self.sExpr, sArch);
3713
3714 @staticmethod
3715 def isInBlockForArch(aoCppCondStack, sArch, iLine):
3716 """ Checks if sArch is included in the current conditional block. """
3717 _ = iLine;
3718 #print('debug: isInBlockForArch(%s,%s); line %s' % (len(aoCppCondStack), sArch, iLine), file = sys.stderr);
3719 for oCond in aoCppCondStack:
3720 if oCond.isArchIncludedInPrimaryBlock(sArch):
3721 if oCond.aoElif or oCond.fInElse:
3722 #print('debug: isInBlockForArch -> False #1', file = sys.stderr);
3723 return False;
3724 #print('debug: isInBlockForArch(%s,%s): in IF-block' % (len(aoCppCondStack), sArch), file = sys.stderr);
3725 else:
3726 fFine = False;
3727 for oElifCond in oCond.aoElif:
3728 if oElifCond.isArchIncludedInPrimaryBlock(sArch):
3729 if oElifCond is not oCond.aoElif[-1] or oCond.fInElse:
3730 #print('debug: isInBlockForArch -> False #3', file = sys.stderr);
3731 return False;
3732 fFine = True;
3733 if not fFine and not oCond.fInElse:
3734 #print('debug: isInBlockForArch -> False #4', file = sys.stderr);
3735 return False;
3736 #print('debug: isInBlockForArch -> True', file = sys.stderr);
3737 return True;
3738
3739 def __init__(self, sSrcFile, asLines, sDefaultMap, sHostArch, oInheritMacrosFrom = None):
3740 self.sSrcFile = sSrcFile;
3741 self.asLines = asLines;
3742 self.iLine = 0;
3743 self.iState = self.kiCode;
3744 self.sComment = '';
3745 self.iCommentLine = 0;
3746 self.aoCurInstrs = [] # type: List[Instruction]
3747 self.oCurFunction = None # type: DecoderFunction
3748 self.iMcBlockInFunc = 0;
3749 self.oCurMcBlock = None # type: McBlock
3750 self.dMacros = {} # type: Dict[str, SimpleParser.Macro]
3751 self.oReMacros = None # type: re ##< Regular expression matching invocations of anything in self.dMacros.
3752 if oInheritMacrosFrom:
3753 self.dMacros = dict(oInheritMacrosFrom.dMacros);
3754 self.oReMacros = oInheritMacrosFrom.oReMacros;
3755 self.aoCppCondStack = [] # type: List[PreprocessorConditional] ##< Preprocessor conditional stack.
3756 self.sHostArch = sHostArch;
3757
3758 assert sDefaultMap in g_dInstructionMaps;
3759 self.oDefaultMap = g_dInstructionMaps[sDefaultMap];
3760
3761 self.cTotalInstr = 0;
3762 self.cTotalStubs = 0;
3763 self.cTotalTagged = 0;
3764 self.cTotalMcBlocks = 0;
3765
3766 self.oReMacroName = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3767 self.oReMnemonic = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3768 self.oReStatsName = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3769 self.oReFunctionName= re.compile(r'^iemOp_[A-Za-z_][A-Za-z0-9_]*$');
3770 self.oReGroupName = re.compile(r'^og_[a-z0-9]+(|_[a-z0-9]+|_[a-z0-9]+_[a-z0-9]+)$');
3771 self.oReDisEnum = re.compile(r'^OP_[A-Z0-9_]+$');
3772 self.oReFunTable = re.compile(r'^(IEM_STATIC|static) +const +PFNIEMOP +g_apfn[A-Za-z0-9_]+ *\[ *\d* *\] *= *$');
3773 self.oReComment = re.compile(r'//.*?$|/\*.*?\*/'); ## Full comments.
3774 self.oReHashDefine2 = re.compile(r'(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)\(([^)]*)\)\s*(.*)\Z'); ##< With arguments.
3775 self.oReHashDefine3 = re.compile(r'(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)[^(]\s*(.*)\Z'); ##< Simple, no arguments.
3776 self.oReMcBeginEnd = re.compile(r'\bIEM_MC_(BEGIN|END|DEFER_TO_CIMPL_[1-5]_RET)\s*\('); ##> Not DEFER_TO_CIMPL_0_RET!
3777 self.fDebug = True;
3778 self.fDebugMc = False;
3779 self.fDebugPreproc = False;
3780
3781 self.dTagHandlers = {
3782 '@opbrief': self.parseTagOpBrief,
3783 '@opdesc': self.parseTagOpDesc,
3784 '@opmnemonic': self.parseTagOpMnemonic,
3785 '@op1': self.parseTagOpOperandN,
3786 '@op2': self.parseTagOpOperandN,
3787 '@op3': self.parseTagOpOperandN,
3788 '@op4': self.parseTagOpOperandN,
3789 '@oppfx': self.parseTagOpPfx,
3790 '@opmaps': self.parseTagOpMaps,
3791 '@opcode': self.parseTagOpcode,
3792 '@opcodesub': self.parseTagOpcodeSub,
3793 '@openc': self.parseTagOpEnc,
3794 #@opfltest: Lists all flags that will be used as input in some way.
3795 '@opfltest': self.parseTagOpEFlags,
3796 #@opflmodify: Lists all EFLAGS modified. Includes @opflset, @opflcleared and @opflundef (if applicable).
3797 '@opflmodify': self.parseTagOpEFlags,
3798 #@opflclear: Lists all flags that will be set (set to 1).
3799 '@opflset': self.parseTagOpEFlags,
3800 #@opflclear: Lists all flags that will be cleared (set to 0).
3801 '@opflclear': self.parseTagOpEFlags,
3802 #@opflundef: List of flag documented as undefined.
3803 '@opflundef': self.parseTagOpEFlags,
3804 #@opflclass: Shorthand for defining flag behaviour (@opfltest, @opfmodify, @opflset, @opflclear, @opflundef).
3805 '@opflclass': self.parseTagOpEFlagsClass,
3806 '@ophints': self.parseTagOpHints,
3807 '@opdisenum': self.parseTagOpDisEnum,
3808 '@opmincpu': self.parseTagOpMinCpu,
3809 '@opcpuid': self.parseTagOpCpuId,
3810 '@opgroup': self.parseTagOpGroup,
3811 '@opunused': self.parseTagOpUnusedInvalid,
3812 '@opinvalid': self.parseTagOpUnusedInvalid,
3813 '@opinvlstyle': self.parseTagOpUnusedInvalid,
3814 '@optest': self.parseTagOpTest,
3815 '@optestign': self.parseTagOpTestIgnore,
3816 '@optestignore': self.parseTagOpTestIgnore,
3817 '@opcopytests': self.parseTagOpCopyTests,
3818 '@oponly': self.parseTagOpOnlyTest,
3819 '@oponlytest': self.parseTagOpOnlyTest,
3820 '@opxcpttype': self.parseTagOpXcptType,
3821 '@opstats': self.parseTagOpStats,
3822 '@opfunction': self.parseTagOpFunction,
3823 '@opdone': self.parseTagOpDone,
3824 };
3825 for i in range(48):
3826 self.dTagHandlers['@optest%u' % (i,)] = self.parseTagOpTestNum;
3827 self.dTagHandlers['@optest[%u]' % (i,)] = self.parseTagOpTestNum;
3828
3829 self.asErrors = [];
3830
3831 def raiseError(self, sMessage):
3832 """
3833 Raise error prefixed with the source and line number.
3834 """
3835 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iLine, sMessage,));
3836
3837 def raiseCommentError(self, iLineInComment, sMessage):
3838 """
3839 Similar to raiseError, but the line number is iLineInComment + self.iCommentLine.
3840 """
3841 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3842
3843 def error(self, sMessage):
3844 """
3845 Adds an error.
3846 returns False;
3847 """
3848 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iLine, sMessage,));
3849 return False;
3850
3851 def errorOnLine(self, iLine, sMessage):
3852 """
3853 Adds an error.
3854 returns False;
3855 """
3856 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, iLine, sMessage,));
3857 return False;
3858
3859 def errorComment(self, iLineInComment, sMessage):
3860 """
3861 Adds a comment error.
3862 returns False;
3863 """
3864 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3865 return False;
3866
3867 def printErrors(self):
3868 """
3869 Print the errors to stderr.
3870 Returns number of errors.
3871 """
3872 if self.asErrors:
3873 sys.stderr.write(u''.join(self.asErrors));
3874 return len(self.asErrors);
3875
3876 def debug(self, sMessage):
3877 """
3878 For debugging.
3879 """
3880 if self.fDebug:
3881 print('debug: %s' % (sMessage,), file = sys.stderr);
3882
3883 def stripComments(self, sLine):
3884 """
3885 Returns sLine with comments stripped.
3886
3887 Complains if traces of incomplete multi-line comments are encountered.
3888 """
3889 sLine = self.oReComment.sub(" ", sLine);
3890 if sLine.find('/*') >= 0 or sLine.find('*/') >= 0:
3891 self.error('Unexpected multi-line comment will not be handled correctly. Please simplify.');
3892 return sLine;
3893
3894 def parseFunctionTable(self, sLine):
3895 """
3896 Parses a PFNIEMOP table, updating/checking the @oppfx value.
3897
3898 Note! Updates iLine as it consumes the whole table.
3899 """
3900
3901 #
3902 # Extract the table name.
3903 #
3904 sName = re.search(r' *([a-zA-Z_0-9]+) *\[', sLine).group(1);
3905 oMap = g_dInstructionMapsByIemName.get(sName);
3906 if not oMap:
3907 self.debug('No map for PFNIEMOP table: %s' % (sName,));
3908 oMap = self.oDefaultMap; # This is wrong wrong wrong.
3909
3910 #
3911 # All but the g_apfnOneByteMap & g_apfnEscF1_E0toFF tables uses four
3912 # entries per byte:
3913 # no prefix, 066h prefix, f3h prefix, f2h prefix
3914 # Those tables has 256 & 32 entries respectively.
3915 #
3916 cEntriesPerByte = 4;
3917 cValidTableLength = 1024;
3918 asPrefixes = ('none', '0x66', '0xf3', '0xf2');
3919
3920 oEntriesMatch = re.search(r'\[ *(256|32) *\]', sLine);
3921 if oEntriesMatch:
3922 cEntriesPerByte = 1;
3923 cValidTableLength = int(oEntriesMatch.group(1));
3924 asPrefixes = (None,);
3925
3926 #
3927 # The next line should be '{' and nothing else.
3928 #
3929 if self.iLine >= len(self.asLines) or not re.match('^ *{ *$', self.asLines[self.iLine]):
3930 return self.errorOnLine(self.iLine + 1, 'Expected lone "{" on line following PFNIEMOP table %s start' % (sName, ));
3931 self.iLine += 1;
3932
3933 #
3934 # Parse till we find the end of the table.
3935 #
3936 iEntry = 0;
3937 while self.iLine < len(self.asLines):
3938 # Get the next line and strip comments and spaces (assumes no
3939 # multi-line comments).
3940 sLine = self.asLines[self.iLine];
3941 self.iLine += 1;
3942 sLine = self.stripComments(sLine).strip();
3943
3944 # Split the line up into entries, expanding IEMOP_X4 usage.
3945 asEntries = sLine.split(',');
3946 for i in range(len(asEntries) - 1, -1, -1):
3947 sEntry = asEntries[i].strip();
3948 if sEntry.startswith('IEMOP_X4(') and sEntry[-1] == ')':
3949 sEntry = (sEntry[len('IEMOP_X4('):-1]).strip();
3950 asEntries.insert(i + 1, sEntry);
3951 asEntries.insert(i + 1, sEntry);
3952 asEntries.insert(i + 1, sEntry);
3953 if sEntry:
3954 asEntries[i] = sEntry;
3955 else:
3956 del asEntries[i];
3957
3958 # Process the entries.
3959 for sEntry in asEntries:
3960 if sEntry in ('};', '}'):
3961 if iEntry != cValidTableLength:
3962 return self.error('Wrong table length for %s: %#x, expected %#x' % (sName, iEntry, cValidTableLength, ));
3963 return True;
3964 if sEntry.startswith('iemOp_Invalid'):
3965 pass; # skip
3966 else:
3967 # Look up matching instruction by function.
3968 sPrefix = asPrefixes[iEntry % cEntriesPerByte];
3969 sOpcode = '%#04x' % (iEntry // cEntriesPerByte);
3970 aoInstr = g_dAllInstructionsByFunction.get(sEntry);
3971 if aoInstr:
3972 if not isinstance(aoInstr, list):
3973 aoInstr = [aoInstr,];
3974 oInstr = None;
3975 for oCurInstr in aoInstr:
3976 if oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix == sPrefix:
3977 pass;
3978 elif oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix is None:
3979 oCurInstr.sPrefix = sPrefix;
3980 elif oCurInstr.sOpcode is None and oCurInstr.sPrefix is None:
3981 oCurInstr.sOpcode = sOpcode;
3982 oCurInstr.sPrefix = sPrefix;
3983 else:
3984 continue;
3985 oInstr = oCurInstr;
3986 break;
3987 if not oInstr:
3988 oInstr = aoInstr[0].copy(oMap = oMap, sOpcode = sOpcode, sPrefix = sPrefix);
3989 aoInstr.append(oInstr);
3990 g_dAllInstructionsByFunction[sEntry] = aoInstr;
3991 g_aoAllInstructions.append(oInstr);
3992 oMap.aoInstructions.append(oInstr);
3993 else:
3994 self.debug('Function "%s", entry %#04x / byte %#04x in %s, is not associated with an instruction.'
3995 % (sEntry, iEntry, iEntry // cEntriesPerByte, sName,));
3996 iEntry += 1;
3997
3998 return self.error('Unexpected end of file in PFNIEMOP table');
3999
4000 def addInstruction(self, iLine = None):
4001 """
4002 Adds an instruction.
4003 """
4004 oInstr = Instruction(self.sSrcFile, self.iLine if iLine is None else iLine);
4005 g_aoAllInstructions.append(oInstr);
4006 self.aoCurInstrs.append(oInstr);
4007 return oInstr;
4008
4009 def deriveMnemonicAndOperandsFromStats(self, oInstr, sStats):
4010 """
4011 Derives the mnemonic and operands from a IEM stats base name like string.
4012 """
4013 if oInstr.sMnemonic is None:
4014 asWords = sStats.split('_');
4015 oInstr.sMnemonic = asWords[0].lower();
4016 if len(asWords) > 1 and not oInstr.aoOperands:
4017 for sType in asWords[1:]:
4018 if sType in g_kdOpTypes:
4019 oInstr.aoOperands.append(Operand(g_kdOpTypes[sType][1], sType));
4020 else:
4021 #return self.error('unknown operand type: %s (instruction: %s)' % (sType, oInstr))
4022 return False;
4023 return True;
4024
4025 def doneInstructionOne(self, oInstr, iLine):
4026 """
4027 Complete the parsing by processing, validating and expanding raw inputs.
4028 """
4029 assert oInstr.iLineCompleted is None;
4030 oInstr.iLineCompleted = iLine;
4031
4032 #
4033 # Specified instructions.
4034 #
4035 if oInstr.cOpTags > 0:
4036 if oInstr.sStats is None:
4037 pass;
4038
4039 #
4040 # Unspecified legacy stuff. We generally only got a few things to go on here.
4041 # /** Opcode 0x0f 0x00 /0. */
4042 # FNIEMOPRM_DEF(iemOp_Grp6_sldt)
4043 #
4044 else:
4045 #if oInstr.sRawOldOpcodes:
4046 #
4047 #if oInstr.sMnemonic:
4048 pass;
4049
4050 #
4051 # Common defaults.
4052 #
4053
4054 # Guess mnemonic and operands from stats if the former is missing.
4055 if oInstr.sMnemonic is None:
4056 if oInstr.sStats is not None:
4057 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sStats);
4058 elif oInstr.sFunction is not None:
4059 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sFunction.replace('iemOp_', ''));
4060
4061 # Derive the disassembler op enum constant from the mnemonic.
4062 if oInstr.sDisEnum is None and oInstr.sMnemonic is not None:
4063 oInstr.sDisEnum = 'OP_' + oInstr.sMnemonic.upper();
4064
4065 # Derive the IEM statistics base name from mnemonic and operand types.
4066 if oInstr.sStats is None:
4067 if oInstr.sFunction is not None:
4068 oInstr.sStats = oInstr.sFunction.replace('iemOp_', '');
4069 elif oInstr.sMnemonic is not None:
4070 oInstr.sStats = oInstr.sMnemonic;
4071 for oOperand in oInstr.aoOperands:
4072 if oOperand.sType:
4073 oInstr.sStats += '_' + oOperand.sType;
4074
4075 # Derive the IEM function name from mnemonic and operand types.
4076 if oInstr.sFunction is None:
4077 if oInstr.sMnemonic is not None:
4078 oInstr.sFunction = 'iemOp_' + oInstr.sMnemonic;
4079 for oOperand in oInstr.aoOperands:
4080 if oOperand.sType:
4081 oInstr.sFunction += '_' + oOperand.sType;
4082 elif oInstr.sStats:
4083 oInstr.sFunction = 'iemOp_' + oInstr.sStats;
4084
4085 #
4086 # Apply default map and then add the instruction to all it's groups.
4087 #
4088 if not oInstr.aoMaps:
4089 oInstr.aoMaps = [ self.oDefaultMap, ];
4090 for oMap in oInstr.aoMaps:
4091 oMap.aoInstructions.append(oInstr);
4092
4093 #
4094 # Derive encoding from operands and maps.
4095 #
4096 if oInstr.sEncoding is None:
4097 if not oInstr.aoOperands:
4098 if oInstr.fUnused and oInstr.sSubOpcode:
4099 oInstr.sEncoding = 'VEX.ModR/M' if oInstr.onlyInVexMaps() else 'ModR/M';
4100 else:
4101 oInstr.sEncoding = 'VEX.fixed' if oInstr.onlyInVexMaps() else 'fixed';
4102 elif oInstr.aoOperands[0].usesModRM():
4103 if (len(oInstr.aoOperands) >= 2 and oInstr.aoOperands[1].sWhere == 'vvvv') \
4104 or oInstr.onlyInVexMaps():
4105 oInstr.sEncoding = 'VEX.ModR/M';
4106 else:
4107 oInstr.sEncoding = 'ModR/M';
4108
4109 #
4110 # Check the opstat value and add it to the opstat indexed dictionary.
4111 #
4112 if oInstr.sStats:
4113 if oInstr.sStats not in g_dAllInstructionsByStat:
4114 g_dAllInstructionsByStat[oInstr.sStats] = oInstr;
4115 else:
4116 self.error('Duplicate opstat value "%s"\nnew: %s\nold: %s'
4117 % (oInstr.sStats, oInstr, g_dAllInstructionsByStat[oInstr.sStats],));
4118
4119 #
4120 # Add to function indexed dictionary. We allow multiple instructions per function.
4121 #
4122 if oInstr.sFunction:
4123 if oInstr.sFunction not in g_dAllInstructionsByFunction:
4124 g_dAllInstructionsByFunction[oInstr.sFunction] = [oInstr,];
4125 else:
4126 g_dAllInstructionsByFunction[oInstr.sFunction].append(oInstr);
4127
4128 #self.debug('%d..%d: %s; %d @op tags' % (oInstr.iLineCreated, oInstr.iLineCompleted, oInstr.sFunction, oInstr.cOpTags));
4129 return True;
4130
4131 def doneInstructions(self, iLineInComment = None, fEndOfFunction = False):
4132 """
4133 Done with current instruction.
4134 """
4135 for oInstr in self.aoCurInstrs:
4136 self.doneInstructionOne(oInstr, self.iLine if iLineInComment is None else self.iCommentLine + iLineInComment);
4137 if oInstr.fStub:
4138 self.cTotalStubs += 1;
4139
4140 self.cTotalInstr += len(self.aoCurInstrs);
4141
4142 self.sComment = '';
4143 self.aoCurInstrs = [];
4144 if fEndOfFunction:
4145 #self.debug('%s: oCurFunction=None' % (self.iLine, ));
4146 if self.oCurFunction:
4147 self.oCurFunction.complete(self.iLine, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine]);
4148 self.oCurFunction = None;
4149 self.iMcBlockInFunc = 0;
4150 return True;
4151
4152 def setInstrunctionAttrib(self, sAttrib, oValue, fOverwrite = False):
4153 """
4154 Sets the sAttrib of all current instruction to oValue. If fOverwrite
4155 is False, only None values and empty strings are replaced.
4156 """
4157 for oInstr in self.aoCurInstrs:
4158 if fOverwrite is not True:
4159 oOldValue = getattr(oInstr, sAttrib);
4160 if oOldValue is not None:
4161 continue;
4162 setattr(oInstr, sAttrib, oValue);
4163
4164 def setInstrunctionArrayAttrib(self, sAttrib, iEntry, oValue, fOverwrite = False):
4165 """
4166 Sets the iEntry of the array sAttrib of all current instruction to oValue.
4167 If fOverwrite is False, only None values and empty strings are replaced.
4168 """
4169 for oInstr in self.aoCurInstrs:
4170 aoArray = getattr(oInstr, sAttrib);
4171 while len(aoArray) <= iEntry:
4172 aoArray.append(None);
4173 if fOverwrite is True or aoArray[iEntry] is None:
4174 aoArray[iEntry] = oValue;
4175
4176 def parseCommentOldOpcode(self, asLines):
4177 """ Deals with 'Opcode 0xff /4' like comments """
4178 asWords = asLines[0].split();
4179 if len(asWords) >= 2 \
4180 and asWords[0] == 'Opcode' \
4181 and ( asWords[1].startswith('0x')
4182 or asWords[1].startswith('0X')):
4183 asWords = asWords[:1];
4184 for iWord, sWord in enumerate(asWords):
4185 if sWord.startswith('0X'):
4186 sWord = '0x' + sWord[:2];
4187 asWords[iWord] = asWords;
4188 self.setInstrunctionAttrib('sRawOldOpcodes', ' '.join(asWords));
4189
4190 return False;
4191
4192 def ensureInstructionForOpTag(self, iTagLine):
4193 """ Ensure there is an instruction for the op-tag being parsed. """
4194 if not self.aoCurInstrs:
4195 self.addInstruction(self.iCommentLine + iTagLine);
4196 for oInstr in self.aoCurInstrs:
4197 oInstr.cOpTags += 1;
4198 if oInstr.cOpTags == 1:
4199 self.cTotalTagged += 1;
4200 return self.aoCurInstrs[-1];
4201
4202 @staticmethod
4203 def flattenSections(aasSections):
4204 """
4205 Flattens multiline sections into stripped single strings.
4206 Returns list of strings, on section per string.
4207 """
4208 asRet = [];
4209 for asLines in aasSections:
4210 if asLines:
4211 asRet.append(' '.join([sLine.strip() for sLine in asLines]));
4212 return asRet;
4213
4214 @staticmethod
4215 def flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = '\n'):
4216 """
4217 Flattens sections into a simple stripped string with newlines as
4218 section breaks. The final section does not sport a trailing newline.
4219 """
4220 # Typical: One section with a single line.
4221 if len(aasSections) == 1 and len(aasSections[0]) == 1:
4222 return aasSections[0][0].strip();
4223
4224 sRet = '';
4225 for iSection, asLines in enumerate(aasSections):
4226 if asLines:
4227 if iSection > 0:
4228 sRet += sSectionSep;
4229 sRet += sLineSep.join([sLine.strip() for sLine in asLines]);
4230 return sRet;
4231
4232
4233
4234 ## @name Tag parsers
4235 ## @{
4236
4237 def parseTagOpBrief(self, sTag, aasSections, iTagLine, iEndLine):
4238 """
4239 Tag: @opbrief
4240 Value: Text description, multiple sections, appended.
4241
4242 Brief description. If not given, it's the first sentence from @opdesc.
4243 """
4244 oInstr = self.ensureInstructionForOpTag(iTagLine);
4245
4246 # Flatten and validate the value.
4247 sBrief = self.flattenAllSections(aasSections);
4248 if not sBrief:
4249 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
4250 if sBrief[-1] != '.':
4251 sBrief = sBrief + '.';
4252 if len(sBrief) > 180:
4253 return self.errorComment(iTagLine, '%s: value too long (max 180 chars): %s' % (sTag, sBrief));
4254 offDot = sBrief.find('.');
4255 while 0 <= offDot < len(sBrief) - 1 and sBrief[offDot + 1] != ' ':
4256 offDot = sBrief.find('.', offDot + 1);
4257 if offDot >= 0 and offDot != len(sBrief) - 1:
4258 return self.errorComment(iTagLine, '%s: only one sentence: %s' % (sTag, sBrief));
4259
4260 # Update the instruction.
4261 if oInstr.sBrief is not None:
4262 return self.errorComment(iTagLine, '%s: attempting to overwrite brief "%s" with "%s"'
4263 % (sTag, oInstr.sBrief, sBrief,));
4264 _ = iEndLine;
4265 return True;
4266
4267 def parseTagOpDesc(self, sTag, aasSections, iTagLine, iEndLine):
4268 """
4269 Tag: @opdesc
4270 Value: Text description, multiple sections, appended.
4271
4272 It is used to describe instructions.
4273 """
4274 oInstr = self.ensureInstructionForOpTag(iTagLine);
4275 if aasSections:
4276 oInstr.asDescSections.extend(self.flattenSections(aasSections));
4277 return True;
4278
4279 _ = sTag; _ = iEndLine;
4280 return True;
4281
4282 def parseTagOpMnemonic(self, sTag, aasSections, iTagLine, iEndLine):
4283 """
4284 Tag: @opmenmonic
4285 Value: mnemonic
4286
4287 The 'mnemonic' value must be a valid C identifier string. Because of
4288 prefixes, groups and whatnot, there times when the mnemonic isn't that
4289 of an actual assembler mnemonic.
4290 """
4291 oInstr = self.ensureInstructionForOpTag(iTagLine);
4292
4293 # Flatten and validate the value.
4294 sMnemonic = self.flattenAllSections(aasSections);
4295 if not self.oReMnemonic.match(sMnemonic):
4296 return self.errorComment(iTagLine, '%s: invalid menmonic name: "%s"' % (sTag, sMnemonic,));
4297 if oInstr.sMnemonic is not None:
4298 return self.errorComment(iTagLine, '%s: attempting to overwrite menmonic "%s" with "%s"'
4299 % (sTag, oInstr.sMnemonic, sMnemonic,));
4300 oInstr.sMnemonic = sMnemonic
4301
4302 _ = iEndLine;
4303 return True;
4304
4305 def parseTagOpOperandN(self, sTag, aasSections, iTagLine, iEndLine):
4306 """
4307 Tags: @op1, @op2, @op3, @op4
4308 Value: [where:]type
4309
4310 The 'where' value indicates where the operand is found, like the 'reg'
4311 part of the ModR/M encoding. See Instruction.kdOperandLocations for
4312 a list.
4313
4314 The 'type' value indicates the operand type. These follow the types
4315 given in the opcode tables in the CPU reference manuals.
4316 See Instruction.kdOperandTypes for a list.
4317
4318 """
4319 oInstr = self.ensureInstructionForOpTag(iTagLine);
4320 idxOp = int(sTag[-1]) - 1;
4321 assert 0 <= idxOp < 4;
4322
4323 # flatten, split up, and validate the "where:type" value.
4324 sFlattened = self.flattenAllSections(aasSections);
4325 asSplit = sFlattened.split(':');
4326 if len(asSplit) == 1:
4327 sType = asSplit[0];
4328 sWhere = None;
4329 elif len(asSplit) == 2:
4330 (sWhere, sType) = asSplit;
4331 else:
4332 return self.errorComment(iTagLine, 'expected %s value on format "[<where>:]<type>" not "%s"' % (sTag, sFlattened,));
4333
4334 if sType not in g_kdOpTypes:
4335 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
4336 % (sTag, sType, ', '.join(g_kdOpTypes.keys()),));
4337 if sWhere is None:
4338 sWhere = g_kdOpTypes[sType][1];
4339 elif sWhere not in g_kdOpLocations:
4340 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
4341 % (sTag, sWhere, ', '.join(g_kdOpLocations.keys()),));
4342
4343 # Insert the operand, refusing to overwrite an existing one.
4344 while idxOp >= len(oInstr.aoOperands):
4345 oInstr.aoOperands.append(None);
4346 if oInstr.aoOperands[idxOp] is not None:
4347 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s:%s" with "%s:%s"'
4348 % ( sTag, oInstr.aoOperands[idxOp].sWhere, oInstr.aoOperands[idxOp].sType,
4349 sWhere, sType,));
4350 oInstr.aoOperands[idxOp] = Operand(sWhere, sType);
4351
4352 _ = iEndLine;
4353 return True;
4354
4355 def parseTagOpMaps(self, sTag, aasSections, iTagLine, iEndLine):
4356 """
4357 Tag: @opmaps
4358 Value: map[,map2]
4359
4360 Indicates which maps the instruction is in. There is a default map
4361 associated with each input file.
4362 """
4363 oInstr = self.ensureInstructionForOpTag(iTagLine);
4364
4365 # Flatten, split up and validate the value.
4366 sFlattened = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',');
4367 asMaps = sFlattened.split(',');
4368 if not asMaps:
4369 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
4370 for sMap in asMaps:
4371 if sMap not in g_dInstructionMaps:
4372 return self.errorComment(iTagLine, '%s: invalid map value: %s (valid values: %s)'
4373 % (sTag, sMap, ', '.join(g_dInstructionMaps.keys()),));
4374
4375 # Add the maps to the current list. Throw errors on duplicates.
4376 for oMap in oInstr.aoMaps:
4377 if oMap.sName in asMaps:
4378 return self.errorComment(iTagLine, '%s: duplicate map assignment: %s' % (sTag, oMap.sName));
4379
4380 for sMap in asMaps:
4381 oMap = g_dInstructionMaps[sMap];
4382 if oMap not in oInstr.aoMaps:
4383 oInstr.aoMaps.append(oMap);
4384 else:
4385 self.errorComment(iTagLine, '%s: duplicate map assignment (input): %s' % (sTag, sMap));
4386
4387 _ = iEndLine;
4388 return True;
4389
4390 def parseTagOpPfx(self, sTag, aasSections, iTagLine, iEndLine):
4391 """
4392 Tag: @oppfx
4393 Value: n/a|none|0x66|0xf3|0xf2|!0xf3
4394
4395 Required prefix for the instruction. (In a (E)VEX context this is the
4396 value of the 'pp' field rather than an actual prefix.)
4397 """
4398 oInstr = self.ensureInstructionForOpTag(iTagLine);
4399
4400 # Flatten and validate the value.
4401 sFlattened = self.flattenAllSections(aasSections);
4402 asPrefixes = sFlattened.split();
4403 if len(asPrefixes) > 1:
4404 return self.errorComment(iTagLine, '%s: max one prefix: %s' % (sTag, asPrefixes,));
4405
4406 sPrefix = asPrefixes[0].lower();
4407 if sPrefix == 'none':
4408 sPrefix = 'none';
4409 elif sPrefix == 'n/a':
4410 sPrefix = None;
4411 else:
4412 if len(sPrefix) == 2:
4413 sPrefix = '0x' + sPrefix;
4414 if not _isValidOpcodeByte(sPrefix):
4415 if sPrefix != '!0xf3':
4416 return self.errorComment(iTagLine, '%s: invalid prefix: %s' % (sTag, sPrefix,));
4417
4418 if sPrefix is not None and sPrefix not in g_kdPrefixes:
4419 return self.errorComment(iTagLine, '%s: invalid prefix: %s (valid %s)' % (sTag, sPrefix, g_kdPrefixes,));
4420
4421 # Set it.
4422 if oInstr.sPrefix is not None:
4423 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sPrefix, sPrefix,));
4424 oInstr.sPrefix = sPrefix;
4425
4426 _ = iEndLine;
4427 return True;
4428
4429 def parseTagOpcode(self, sTag, aasSections, iTagLine, iEndLine):
4430 """
4431 Tag: @opcode
4432 Value: 0x?? | /reg (TODO: | mr/reg | 11 /reg | !11 /reg | 11 mr/reg | !11 mr/reg)
4433
4434 The opcode byte or sub-byte for the instruction in the context of a map.
4435 """
4436 oInstr = self.ensureInstructionForOpTag(iTagLine);
4437
4438 # Flatten and validate the value.
4439 sOpcode = self.flattenAllSections(aasSections);
4440 if _isValidOpcodeByte(sOpcode):
4441 pass;
4442 elif len(sOpcode) == 2 and sOpcode.startswith('/') and sOpcode[-1] in '012345678':
4443 pass;
4444 elif len(sOpcode) == 4 and sOpcode.startswith('11/') and sOpcode[-1] in '012345678':
4445 pass;
4446 elif len(sOpcode) == 5 and sOpcode.startswith('!11/') and sOpcode[-1] in '012345678':
4447 pass;
4448 else:
4449 return self.errorComment(iTagLine, '%s: invalid opcode: %s' % (sTag, sOpcode,));
4450
4451 # Set it.
4452 if oInstr.sOpcode is not None:
4453 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sOpcode, sOpcode,));
4454 oInstr.sOpcode = sOpcode;
4455
4456 _ = iEndLine;
4457 return True;
4458
4459 def parseTagOpcodeSub(self, sTag, aasSections, iTagLine, iEndLine):
4460 """
4461 Tag: @opcodesub
4462 Value: none | 11 mr/reg | !11 mr/reg | rex.w=0 | rex.w=1 | vex.l=0 | vex.l=1
4463 | 11 mr/reg vex.l=0 | 11 mr/reg vex.l=1 | !11 mr/reg vex.l=0 | !11 mr/reg vex.l=1
4464 | !11 rex.w=0 | !11 mr/reg rex.w=0
4465 | !11 rex.w=1 | !11 mr/reg rex.w=1
4466
4467 This is a simple way of dealing with encodings where the mod=3 and mod!=3
4468 represents exactly two different instructions. The more proper way would
4469 be to go via maps with two members, but this is faster.
4470 """
4471 oInstr = self.ensureInstructionForOpTag(iTagLine);
4472
4473 # Flatten and validate the value.
4474 sSubOpcode = self.flattenAllSections(aasSections);
4475 if sSubOpcode not in g_kdSubOpcodes:
4476 return self.errorComment(iTagLine, '%s: invalid sub opcode: %s (valid: %s)'
4477 % (sTag, sSubOpcode, ', '.join(sorted(g_kdSubOpcodes.keys())),));
4478 sSubOpcode = g_kdSubOpcodes[sSubOpcode][0];
4479
4480 # Set it.
4481 if oInstr.sSubOpcode is not None:
4482 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4483 % ( sTag, oInstr.sSubOpcode, sSubOpcode,));
4484 oInstr.sSubOpcode = sSubOpcode;
4485
4486 _ = iEndLine;
4487 return True;
4488
4489 def parseTagOpEnc(self, sTag, aasSections, iTagLine, iEndLine):
4490 """
4491 Tag: @openc
4492 Value: ModR/M|fixed|prefix|<map name>
4493
4494 The instruction operand encoding style.
4495 """
4496 oInstr = self.ensureInstructionForOpTag(iTagLine);
4497
4498 # Flatten and validate the value.
4499 sEncoding = self.flattenAllSections(aasSections);
4500 if sEncoding in g_kdEncodings:
4501 pass;
4502 elif sEncoding in g_dInstructionMaps:
4503 pass;
4504 elif not _isValidOpcodeByte(sEncoding):
4505 return self.errorComment(iTagLine, '%s: invalid encoding: %s' % (sTag, sEncoding,));
4506
4507 # Set it.
4508 if oInstr.sEncoding is not None:
4509 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4510 % ( sTag, oInstr.sEncoding, sEncoding,));
4511 oInstr.sEncoding = sEncoding;
4512
4513 _ = iEndLine;
4514 return True;
4515
4516 ## EFlags tag to Instruction attribute name.
4517 kdOpFlagToAttr = {
4518 '@opfltest': 'asFlTest',
4519 '@opflmodify': 'asFlModify',
4520 '@opflundef': 'asFlUndefined',
4521 '@opflset': 'asFlSet',
4522 '@opflclear': 'asFlClear',
4523 };
4524
4525 def parseTagOpEFlags(self, sTag, aasSections, iTagLine, iEndLine):
4526 """
4527 Tags: @opfltest, @opflmodify, @opflundef, @opflset, @opflclear
4528 Value: <eflags specifier>
4529
4530 """
4531 oInstr = self.ensureInstructionForOpTag(iTagLine);
4532
4533 # Flatten, split up and validate the values.
4534 asFlags = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',').split(',');
4535 if len(asFlags) == 1 and asFlags[0].lower() == 'none':
4536 asFlags = [];
4537 else:
4538 fRc = True;
4539 for iFlag, sFlag in enumerate(asFlags):
4540 if sFlag not in g_kdEFlagsMnemonics:
4541 if sFlag.strip() in g_kdEFlagsMnemonics:
4542 asFlags[iFlag] = sFlag.strip();
4543 else:
4544 fRc = self.errorComment(iTagLine, '%s: invalid EFLAGS value: %s' % (sTag, sFlag,));
4545 if not fRc:
4546 return False;
4547
4548 # Set them.
4549 asOld = getattr(oInstr, self.kdOpFlagToAttr[sTag]);
4550 if asOld is not None and len(asOld) > 0:
4551 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, asOld, asFlags,));
4552 setattr(oInstr, self.kdOpFlagToAttr[sTag], asFlags);
4553
4554 _ = iEndLine;
4555 return True;
4556
4557 ## EFLAGS class definitions with their attribute lists.
4558 kdEFlagsClasses = {
4559 'arithmetic': { # add, sub, ...
4560 'asFlTest': [],
4561 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4562 'asFlClear': [],
4563 'asFlSet': [],
4564 'asFlUndefined': [],
4565 },
4566 'arithmetic_carry': { # adc, sbb, ...
4567 'asFlTest': [ 'cf', ],
4568 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4569 'asFlClear': [],
4570 'asFlSet': [],
4571 'asFlUndefined': [],
4572 },
4573 'incdec': {
4574 'asFlTest': [],
4575 'asFlModify': [ 'pf', 'af', 'zf', 'sf', 'of', ], # leaves CF alone
4576 'asFlClear': [],
4577 'asFlSet': [],
4578 'asFlUndefined': [],
4579 },
4580 'division': { ## @todo specify intel/amd differences...
4581 'asFlTest': [ 'pf', 'af', 'zf', 'sf', ], # Intel leaves all flags unchanged.
4582 'asFlModify': [ 'pf', 'af', 'zf', 'sf', ], # While AMD sets AF and clears PF, ZF & SF, leaving CF and OF alone.
4583 'asFlClear': [],
4584 'asFlSet': [],
4585 'asFlUndefined': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4586 },
4587 'multiply': { ## @todo specify intel/amd differences...
4588 'asFlTest': [ 'pf', 'af', 'zf', 'sf', ], # AMD leaves these unchanged, so we have to delcare them as inputs.
4589 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of' ], # Intel always modifies all flags, but how differs
4590 'asFlClear': [], # between IMUL and MUL.
4591 'asFlSet': [],
4592 'asFlUndefined': [ 'pf', 'af', 'zf', 'sf', ],
4593 },
4594 'logical': { # and, or, xor, ...
4595 'asFlTest': [],
4596 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4597 'asFlClear': [ 'cf', 'af', 'of', ], # 'af' is undefined, but tstIEMAImpl indicates that it is cleared.
4598 'asFlSet': [],
4599 'asFlUndefined': [ 'af', ],
4600 },
4601 'rotate_1': { # rol and ror with fixed 1 shift count
4602 'asFlTest': [],
4603 'asFlModify': [ 'cf', 'of', ],
4604 'asFlClear': [],
4605 'asFlSet': [],
4606 'asFlUndefined': [],
4607 },
4608 'rotate_count': { # rol and ror w/o fixed 1 shift count
4609 'asFlTest': [ 'cf', 'of', ], # If the count is zero, nothing changes.
4610 'asFlModify': [ 'cf', 'of', ],
4611 'asFlClear': [],
4612 'asFlSet': [],
4613 'asFlUndefined': [ 'of', ],
4614 },
4615 'rotate_carry_1': { # rcl and rcr with fixed 1 shift count
4616 'asFlTest': [ 'cf', ],
4617 'asFlModify': [ 'cf', 'of', ],
4618 'asFlClear': [],
4619 'asFlSet': [],
4620 'asFlUndefined': [],
4621 },
4622 'rotate_carry_count': { # rcl and rcr w/o fixed 1 shift count
4623 'asFlTest': [ 'cf', 'of', ], # If the count is zero, nothing changes, so 'of' is also input.
4624 'asFlModify': [ 'cf', 'of', ],
4625 'asFlClear': [],
4626 'asFlSet': [],
4627 'asFlUndefined': [ 'of', ],
4628 },
4629 'shift_1': { # shl, shr or sar with fixed 1 count.
4630 'asFlTest': [],
4631 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4632 'asFlClear': [],
4633 'asFlSet': [],
4634 'asFlUndefined': [ 'af', ],
4635 },
4636 'shift_count': { # shl, shr or sar w/o fixed 1 shift count
4637 'asFlTest': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ], # If the count is zero, nothing is changed.
4638 'asFlModify': [ 'cf', 'pf', 'af', 'zf', 'sf', 'of', ],
4639 'asFlClear': [],
4640 'asFlSet': [],
4641 'asFlUndefined': [ 'af', 'of', ],
4642 },
4643 'bitmap': { # bt, btc, btr, btc
4644 'asFlTest': [],
4645 'asFlModify': [ 'cf', ],
4646 'asFlClear': [],
4647 'asFlSet': [],
4648 'asFlUndefined': [ 'pf', 'af', 'zf', 'sf', 'of', ], # tstIEMAImpl indicates that they aren't modified.
4649 },
4650 'unchanged': {
4651 'asFlTest': [],
4652 'asFlModify': [],
4653 'asFlClear': [],
4654 'asFlSet': [],
4655 'asFlUndefined': [],
4656 },
4657 };
4658 def parseTagOpEFlagsClass(self, sTag, aasSections, iTagLine, iEndLine):
4659 """
4660 Tags: @opflclass
4661 Value: arithmetic, logical, ...
4662
4663 """
4664 oInstr = self.ensureInstructionForOpTag(iTagLine);
4665
4666 # Flatten and validate the value.
4667 sClass = self.flattenAllSections(aasSections);
4668 kdAttribs = self.kdEFlagsClasses.get(sClass);
4669 if not kdAttribs:
4670 return self.errorComment(iTagLine, '%s: Unknown EFLAGS class: %s (valid: %s)'
4671 % (sTag, sClass, ', '.join(sorted(self.kdEFlagsClasses.keys())),));
4672
4673 # Set the attributes.
4674 for sAttrib, asFlags in kdAttribs.items():
4675 asOld = getattr(oInstr, sAttrib);
4676 if asOld is not None:
4677 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s" for %s'
4678 % (sTag, asOld, asFlags, sAttrib));
4679 setattr(oInstr, sAttrib, asFlags);
4680
4681 _ = iEndLine;
4682 return True;
4683
4684 def parseTagOpHints(self, sTag, aasSections, iTagLine, iEndLine):
4685 """
4686 Tag: @ophints
4687 Value: Comma or space separated list of flags and hints.
4688
4689 This covers the disassembler flags table and more.
4690 """
4691 oInstr = self.ensureInstructionForOpTag(iTagLine);
4692
4693 # Flatten as a space separated list, split it up and validate the values.
4694 asHints = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4695 if len(asHints) == 1 and asHints[0].lower() == 'none':
4696 asHints = [];
4697 else:
4698 fRc = True;
4699 for iHint, sHint in enumerate(asHints):
4700 if sHint not in g_kdHints:
4701 if sHint.strip() in g_kdHints:
4702 sHint[iHint] = sHint.strip();
4703 else:
4704 fRc = self.errorComment(iTagLine, '%s: invalid hint value: %s' % (sTag, sHint,));
4705 if not fRc:
4706 return False;
4707
4708 # Append them.
4709 for sHint in asHints:
4710 if sHint not in oInstr.dHints:
4711 oInstr.dHints[sHint] = True; # (dummy value, using dictionary for speed)
4712 else:
4713 self.errorComment(iTagLine, '%s: duplicate hint: %s' % ( sTag, sHint,));
4714
4715 _ = iEndLine;
4716 return True;
4717
4718 def parseTagOpDisEnum(self, sTag, aasSections, iTagLine, iEndLine):
4719 """
4720 Tag: @opdisenum
4721 Value: OP_XXXX
4722
4723 This is for select a specific (legacy) disassembler enum value for the
4724 instruction.
4725 """
4726 oInstr = self.ensureInstructionForOpTag(iTagLine);
4727
4728 # Flatten and split.
4729 asWords = self.flattenAllSections(aasSections).split();
4730 if len(asWords) != 1:
4731 self.errorComment(iTagLine, '%s: expected exactly one value: %s' % (sTag, asWords,));
4732 if not asWords:
4733 return False;
4734 sDisEnum = asWords[0];
4735 if not self.oReDisEnum.match(sDisEnum):
4736 return self.errorComment(iTagLine, '%s: invalid disassembler OP_XXXX enum: %s (pattern: %s)'
4737 % (sTag, sDisEnum, self.oReDisEnum.pattern));
4738
4739 # Set it.
4740 if oInstr.sDisEnum is not None:
4741 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % (sTag, oInstr.sDisEnum, sDisEnum,));
4742 oInstr.sDisEnum = sDisEnum;
4743
4744 _ = iEndLine;
4745 return True;
4746
4747 def parseTagOpMinCpu(self, sTag, aasSections, iTagLine, iEndLine):
4748 """
4749 Tag: @opmincpu
4750 Value: <simple CPU name>
4751
4752 Indicates when this instruction was introduced.
4753 """
4754 oInstr = self.ensureInstructionForOpTag(iTagLine);
4755
4756 # Flatten the value, split into words, make sure there's just one, valid it.
4757 asCpus = self.flattenAllSections(aasSections).split();
4758 if len(asCpus) > 1:
4759 self.errorComment(iTagLine, '%s: exactly one CPU name, please: %s' % (sTag, ' '.join(asCpus),));
4760
4761 sMinCpu = asCpus[0];
4762 if sMinCpu in g_kdCpuNames:
4763 oInstr.sMinCpu = sMinCpu;
4764 else:
4765 return self.errorComment(iTagLine, '%s: invalid CPU name: %s (names: %s)'
4766 % (sTag, sMinCpu, ','.join(sorted(g_kdCpuNames)),));
4767
4768 # Set it.
4769 if oInstr.sMinCpu is None:
4770 oInstr.sMinCpu = sMinCpu;
4771 elif oInstr.sMinCpu != sMinCpu:
4772 self.errorComment(iTagLine, '%s: attemting to overwrite "%s" with "%s"' % (sTag, oInstr.sMinCpu, sMinCpu,));
4773
4774 _ = iEndLine;
4775 return True;
4776
4777 def parseTagOpCpuId(self, sTag, aasSections, iTagLine, iEndLine):
4778 """
4779 Tag: @opcpuid
4780 Value: none | <CPUID flag specifier>
4781
4782 CPUID feature bit which is required for the instruction to be present.
4783 """
4784 oInstr = self.ensureInstructionForOpTag(iTagLine);
4785
4786 # Flatten as a space separated list, split it up and validate the values.
4787 asCpuIds = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4788 if len(asCpuIds) == 1 and asCpuIds[0].lower() == 'none':
4789 asCpuIds = [];
4790 else:
4791 fRc = True;
4792 for iCpuId, sCpuId in enumerate(asCpuIds):
4793 if sCpuId not in g_kdCpuIdFlags:
4794 if sCpuId.strip() in g_kdCpuIdFlags:
4795 sCpuId[iCpuId] = sCpuId.strip();
4796 else:
4797 fRc = self.errorComment(iTagLine, '%s: invalid CPUID value: %s' % (sTag, sCpuId,));
4798 if not fRc:
4799 return False;
4800
4801 # Append them.
4802 for sCpuId in asCpuIds:
4803 if sCpuId not in oInstr.asCpuIds:
4804 oInstr.asCpuIds.append(sCpuId);
4805 else:
4806 self.errorComment(iTagLine, '%s: duplicate CPUID: %s' % ( sTag, sCpuId,));
4807
4808 _ = iEndLine;
4809 return True;
4810
4811 def parseTagOpGroup(self, sTag, aasSections, iTagLine, iEndLine):
4812 """
4813 Tag: @opgroup
4814 Value: op_grp1[_subgrp2[_subsubgrp3]]
4815
4816 Instruction grouping.
4817 """
4818 oInstr = self.ensureInstructionForOpTag(iTagLine);
4819
4820 # Flatten as a space separated list, split it up and validate the values.
4821 asGroups = self.flattenAllSections(aasSections).split();
4822 if len(asGroups) != 1:
4823 return self.errorComment(iTagLine, '%s: exactly one group, please: %s' % (sTag, asGroups,));
4824 sGroup = asGroups[0];
4825 if not self.oReGroupName.match(sGroup):
4826 return self.errorComment(iTagLine, '%s: invalid group name: %s (valid: %s)'
4827 % (sTag, sGroup, self.oReGroupName.pattern));
4828
4829 # Set it.
4830 if oInstr.sGroup is not None:
4831 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sGroup, sGroup,));
4832 oInstr.sGroup = sGroup;
4833
4834 _ = iEndLine;
4835 return True;
4836
4837 def parseTagOpUnusedInvalid(self, sTag, aasSections, iTagLine, iEndLine):
4838 """
4839 Tag: @opunused, @opinvalid, @opinvlstyle
4840 Value: <invalid opcode behaviour style>
4841
4842 The @opunused indicates the specification is for a currently unused
4843 instruction encoding.
4844
4845 The @opinvalid indicates the specification is for an invalid currently
4846 instruction encoding (like UD2).
4847
4848 The @opinvlstyle just indicates how CPUs decode the instruction when
4849 not supported (@opcpuid, @opmincpu) or disabled.
4850 """
4851 oInstr = self.ensureInstructionForOpTag(iTagLine);
4852
4853 # Flatten as a space separated list, split it up and validate the values.
4854 asStyles = self.flattenAllSections(aasSections).split();
4855 if len(asStyles) != 1:
4856 return self.errorComment(iTagLine, '%s: exactly one invalid behviour style, please: %s' % (sTag, asStyles,));
4857 sStyle = asStyles[0];
4858 if sStyle not in g_kdInvalidStyles:
4859 return self.errorComment(iTagLine, '%s: invalid invalid behaviour style: %s (valid: %s)'
4860 % (sTag, sStyle, g_kdInvalidStyles.keys(),));
4861 # Set it.
4862 if oInstr.sInvalidStyle is not None:
4863 return self.errorComment(iTagLine,
4864 '%s: attempting to overwrite "%s" with "%s" (only one @opunused, @opinvalid, @opinvlstyle)'
4865 % ( sTag, oInstr.sInvalidStyle, sStyle,));
4866 oInstr.sInvalidStyle = sStyle;
4867 if sTag == '@opunused':
4868 oInstr.fUnused = True;
4869 elif sTag == '@opinvalid':
4870 oInstr.fInvalid = True;
4871
4872 _ = iEndLine;
4873 return True;
4874
4875 def parseTagOpTest(self, sTag, aasSections, iTagLine, iEndLine): # pylint: disable=too-many-locals
4876 """
4877 Tag: @optest
4878 Value: [<selectors>[ ]?] <inputs> -> <outputs>
4879 Example: mode==64bit / in1=0xfffffffe:dw in2=1:dw -> out1=0xffffffff:dw outfl=a?,p?
4880
4881 The main idea here is to generate basic instruction tests.
4882
4883 The probably simplest way of handling the diverse input, would be to use
4884 it to produce size optimized byte code for a simple interpreter that
4885 modifies the register input and output states.
4886
4887 An alternative to the interpreter would be creating multiple tables,
4888 but that becomes rather complicated wrt what goes where and then to use
4889 them in an efficient manner.
4890 """
4891 oInstr = self.ensureInstructionForOpTag(iTagLine);
4892
4893 #
4894 # Do it section by section.
4895 #
4896 for asSectionLines in aasSections:
4897 #
4898 # Sort the input into outputs, inputs and selector conditions.
4899 #
4900 sFlatSection = self.flattenAllSections([asSectionLines,]);
4901 if not sFlatSection:
4902 self.errorComment(iTagLine, '%s: missing value (dbg: aasSections=%s)' % ( sTag, aasSections));
4903 continue;
4904 oTest = InstructionTest(oInstr);
4905
4906 asSelectors = [];
4907 asInputs = [];
4908 asOutputs = [];
4909 asCur = asOutputs;
4910 fRc = True;
4911 asWords = sFlatSection.split();
4912 for iWord in range(len(asWords) - 1, -1, -1):
4913 sWord = asWords[iWord];
4914 # Check for array switchers.
4915 if sWord == '->':
4916 if asCur != asOutputs:
4917 fRc = self.errorComment(iTagLine, '%s: "->" shall only occure once: %s' % (sTag, sFlatSection,));
4918 break;
4919 asCur = asInputs;
4920 elif sWord == '/':
4921 if asCur != asInputs:
4922 fRc = self.errorComment(iTagLine, '%s: "/" shall only occure once: %s' % (sTag, sFlatSection,));
4923 break;
4924 asCur = asSelectors;
4925 else:
4926 asCur.insert(0, sWord);
4927
4928 #
4929 # Validate and add selectors.
4930 #
4931 for sCond in asSelectors:
4932 sCondExp = TestSelector.kdPredicates.get(sCond, sCond);
4933 oSelector = None;
4934 for sOp in TestSelector.kasCompareOps:
4935 off = sCondExp.find(sOp);
4936 if off >= 0:
4937 sVariable = sCondExp[:off];
4938 sValue = sCondExp[off + len(sOp):];
4939 if sVariable in TestSelector.kdVariables:
4940 if sValue in TestSelector.kdVariables[sVariable]:
4941 oSelector = TestSelector(sVariable, sOp, sValue);
4942 else:
4943 self.errorComment(iTagLine, '%s: invalid condition value "%s" in "%s" (valid: %s)'
4944 % ( sTag, sValue, sCond,
4945 TestSelector.kdVariables[sVariable].keys(),));
4946 else:
4947 self.errorComment(iTagLine, '%s: invalid condition variable "%s" in "%s" (valid: %s)'
4948 % ( sTag, sVariable, sCond, TestSelector.kdVariables.keys(),));
4949 break;
4950 if oSelector is not None:
4951 for oExisting in oTest.aoSelectors:
4952 if oExisting.sVariable == oSelector.sVariable:
4953 self.errorComment(iTagLine, '%s: already have a selector for variable "%s" (existing: %s, new: %s)'
4954 % ( sTag, oSelector.sVariable, oExisting, oSelector,));
4955 oTest.aoSelectors.append(oSelector);
4956 else:
4957 fRc = self.errorComment(iTagLine, '%s: failed to parse selector: %s' % ( sTag, sCond,));
4958
4959 #
4960 # Validate outputs and inputs, adding them to the test as we go along.
4961 #
4962 for asItems, sDesc, aoDst in [ (asInputs, 'input', oTest.aoInputs), (asOutputs, 'output', oTest.aoOutputs)]:
4963 asValidFieldKinds = [ 'both', sDesc, ];
4964 for sItem in asItems:
4965 oItem = None;
4966 for sOp in TestInOut.kasOperators:
4967 off = sItem.find(sOp);
4968 if off < 0:
4969 continue;
4970 sField = sItem[:off];
4971 sValueType = sItem[off + len(sOp):];
4972 if sField in TestInOut.kdFields \
4973 and TestInOut.kdFields[sField][1] in asValidFieldKinds:
4974 asSplit = sValueType.split(':', 1);
4975 sValue = asSplit[0];
4976 sType = asSplit[1] if len(asSplit) > 1 else TestInOut.kdFields[sField][0];
4977 if sType in TestInOut.kdTypes:
4978 oValid = TestInOut.kdTypes[sType].validate(sValue);
4979 if oValid is True:
4980 if not TestInOut.kdTypes[sType].isAndOrPair(sValue) or sOp == '&|=':
4981 oItem = TestInOut(sField, sOp, sValue, sType);
4982 else:
4983 self.errorComment(iTagLine, '%s: and-or %s value "%s" can only be used with "&|="'
4984 % ( sTag, sDesc, sItem, ));
4985 else:
4986 self.errorComment(iTagLine, '%s: invalid %s value "%s" in "%s" (type: %s): %s'
4987 % ( sTag, sDesc, sValue, sItem, sType, oValid, ));
4988 else:
4989 self.errorComment(iTagLine, '%s: invalid %s type "%s" in "%s" (valid types: %s)'
4990 % ( sTag, sDesc, sType, sItem, TestInOut.kdTypes.keys(),));
4991 else:
4992 self.errorComment(iTagLine, '%s: invalid %s field "%s" in "%s"\nvalid fields: %s'
4993 % ( sTag, sDesc, sField, sItem,
4994 ', '.join([sKey for sKey, asVal in TestInOut.kdFields.items()
4995 if asVal[1] in asValidFieldKinds]),));
4996 break;
4997 if oItem is not None:
4998 for oExisting in aoDst:
4999 if oExisting.sField == oItem.sField and oExisting.sOp == oItem.sOp:
5000 self.errorComment(iTagLine,
5001 '%s: already have a "%s" assignment for field "%s" (existing: %s, new: %s)'
5002 % ( sTag, oItem.sOp, oItem.sField, oExisting, oItem,));
5003 aoDst.append(oItem);
5004 else:
5005 fRc = self.errorComment(iTagLine, '%s: failed to parse assignment: %s' % ( sTag, sItem,));
5006
5007 #
5008 # .
5009 #
5010 if fRc:
5011 oInstr.aoTests.append(oTest);
5012 else:
5013 self.errorComment(iTagLine, '%s: failed to parse test: %s' % (sTag, ' '.join(asWords),));
5014 self.errorComment(iTagLine, '%s: asSelectors=%s / asInputs=%s -> asOutputs=%s'
5015 % (sTag, asSelectors, asInputs, asOutputs,));
5016
5017 _ = iEndLine;
5018 return True;
5019
5020 def parseTagOpTestNum(self, sTag, aasSections, iTagLine, iEndLine):
5021 """
5022 Numbered @optest tag. Either @optest42 or @optest[42].
5023 """
5024 oInstr = self.ensureInstructionForOpTag(iTagLine);
5025
5026 iTest = 0;
5027 if sTag[-1] == ']':
5028 iTest = int(sTag[8:-1]);
5029 else:
5030 iTest = int(sTag[7:]);
5031
5032 if iTest != len(oInstr.aoTests):
5033 self.errorComment(iTagLine, '%s: incorrect test number: %u, actual %u' % (sTag, iTest, len(oInstr.aoTests),));
5034 return self.parseTagOpTest(sTag, aasSections, iTagLine, iEndLine);
5035
5036 def parseTagOpTestIgnore(self, sTag, aasSections, iTagLine, iEndLine):
5037 """
5038 Tag: @optestign | @optestignore
5039 Value: <value is ignored>
5040
5041 This is a simple trick to ignore a test while debugging another.
5042
5043 See also @oponlytest.
5044 """
5045 _ = sTag; _ = aasSections; _ = iTagLine; _ = iEndLine;
5046 return True;
5047
5048 def parseTagOpCopyTests(self, sTag, aasSections, iTagLine, iEndLine):
5049 """
5050 Tag: @opcopytests
5051 Value: <opstat | function> [..]
5052 Example: @opcopytests add_Eb_Gb
5053
5054 Trick to avoid duplicating tests for different encodings of the same
5055 operation.
5056 """
5057 oInstr = self.ensureInstructionForOpTag(iTagLine);
5058
5059 # Flatten, validate and append the copy job to the instruction. We execute
5060 # them after parsing all the input so we can handle forward references.
5061 asToCopy = self.flattenAllSections(aasSections).split();
5062 if not asToCopy:
5063 return self.errorComment(iTagLine, '%s: requires at least on reference value' % (sTag,));
5064 for sToCopy in asToCopy:
5065 if sToCopy not in oInstr.asCopyTests:
5066 if self.oReStatsName.match(sToCopy) or self.oReFunctionName.match(sToCopy):
5067 oInstr.asCopyTests.append(sToCopy);
5068 else:
5069 self.errorComment(iTagLine, '%s: invalid instruction reference (opstat or function) "%s" (valid: %s or %s)'
5070 % (sTag, sToCopy, self.oReStatsName.pattern, self.oReFunctionName.pattern));
5071 else:
5072 self.errorComment(iTagLine, '%s: ignoring duplicate "%s"' % (sTag, sToCopy,));
5073
5074 _ = iEndLine;
5075 return True;
5076
5077 def parseTagOpOnlyTest(self, sTag, aasSections, iTagLine, iEndLine):
5078 """
5079 Tag: @oponlytest | @oponly
5080 Value: none
5081
5082 Only test instructions with this tag. This is a trick that is handy
5083 for singling out one or two new instructions or tests.
5084
5085 See also @optestignore.
5086 """
5087 oInstr = self.ensureInstructionForOpTag(iTagLine);
5088
5089 # Validate and add instruction to only test dictionary.
5090 sValue = self.flattenAllSections(aasSections).strip();
5091 if sValue:
5092 return self.errorComment(iTagLine, '%s: does not take any value: %s' % (sTag, sValue));
5093
5094 if oInstr not in g_aoOnlyTestInstructions:
5095 g_aoOnlyTestInstructions.append(oInstr);
5096
5097 _ = iEndLine;
5098 return True;
5099
5100 def parseTagOpXcptType(self, sTag, aasSections, iTagLine, iEndLine):
5101 """
5102 Tag: @opxcpttype
5103 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]
5104
5105 Sets the SSE or AVX exception type (see SDMv2 2.4, 2.7).
5106 """
5107 oInstr = self.ensureInstructionForOpTag(iTagLine);
5108
5109 # Flatten as a space separated list, split it up and validate the values.
5110 asTypes = self.flattenAllSections(aasSections).split();
5111 if len(asTypes) != 1:
5112 return self.errorComment(iTagLine, '%s: exactly one invalid exception type, please: %s' % (sTag, asTypes,));
5113 sType = asTypes[0];
5114 if sType not in g_kdXcptTypes:
5115 return self.errorComment(iTagLine, '%s: invalid invalid exception type: %s (valid: %s)'
5116 % (sTag, sType, sorted(g_kdXcptTypes.keys()),));
5117 # Set it.
5118 if oInstr.sXcptType is not None:
5119 return self.errorComment(iTagLine,
5120 '%s: attempting to overwrite "%s" with "%s" (only one @opxcpttype)'
5121 % ( sTag, oInstr.sXcptType, sType,));
5122 oInstr.sXcptType = sType;
5123
5124 _ = iEndLine;
5125 return True;
5126
5127 def parseTagOpFunction(self, sTag, aasSections, iTagLine, iEndLine):
5128 """
5129 Tag: @opfunction
5130 Value: <VMM function name>
5131
5132 This is for explicitly setting the IEM function name. Normally we pick
5133 this up from the FNIEMOP_XXX macro invocation after the description, or
5134 generate it from the mnemonic and operands.
5135
5136 It it thought it maybe necessary to set it when specifying instructions
5137 which implementation isn't following immediately or aren't implemented yet.
5138 """
5139 oInstr = self.ensureInstructionForOpTag(iTagLine);
5140
5141 # Flatten and validate the value.
5142 sFunction = self.flattenAllSections(aasSections);
5143 if not self.oReFunctionName.match(sFunction):
5144 return self.errorComment(iTagLine, '%s: invalid VMM function name: "%s" (valid: %s)'
5145 % (sTag, sFunction, self.oReFunctionName.pattern));
5146
5147 if oInstr.sFunction is not None:
5148 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM function name "%s" with "%s"'
5149 % (sTag, oInstr.sFunction, sFunction,));
5150 oInstr.sFunction = sFunction;
5151
5152 _ = iEndLine;
5153 return True;
5154
5155 def parseTagOpStats(self, sTag, aasSections, iTagLine, iEndLine):
5156 """
5157 Tag: @opstats
5158 Value: <VMM statistics base name>
5159
5160 This is for explicitly setting the statistics name. Normally we pick
5161 this up from the IEMOP_MNEMONIC macro invocation, or generate it from
5162 the mnemonic and operands.
5163
5164 It it thought it maybe necessary to set it when specifying instructions
5165 which implementation isn't following immediately or aren't implemented yet.
5166 """
5167 oInstr = self.ensureInstructionForOpTag(iTagLine);
5168
5169 # Flatten and validate the value.
5170 sStats = self.flattenAllSections(aasSections);
5171 if not self.oReStatsName.match(sStats):
5172 return self.errorComment(iTagLine, '%s: invalid VMM statistics name: "%s" (valid: %s)'
5173 % (sTag, sStats, self.oReStatsName.pattern));
5174
5175 if oInstr.sStats is not None:
5176 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM statistics base name "%s" with "%s"'
5177 % (sTag, oInstr.sStats, sStats,));
5178 oInstr.sStats = sStats;
5179
5180 _ = iEndLine;
5181 return True;
5182
5183 def parseTagOpDone(self, sTag, aasSections, iTagLine, iEndLine):
5184 """
5185 Tag: @opdone
5186 Value: none
5187
5188 Used to explictily flush the instructions that have been specified.
5189 """
5190 sFlattened = self.flattenAllSections(aasSections);
5191 if sFlattened != '':
5192 return self.errorComment(iTagLine, '%s: takes no value, found: "%s"' % (sTag, sFlattened,));
5193 _ = sTag; _ = iEndLine;
5194 return self.doneInstructions();
5195
5196 ## @}
5197
5198
5199 def parseComment(self):
5200 """
5201 Parse the current comment (self.sComment).
5202
5203 If it's a opcode specifiying comment, we reset the macro stuff.
5204 """
5205 #
5206 # Reject if comment doesn't seem to contain anything interesting.
5207 #
5208 if self.sComment.find('Opcode') < 0 \
5209 and self.sComment.find('@') < 0:
5210 return False;
5211
5212 #
5213 # Split the comment into lines, removing leading asterisks and spaces.
5214 # Also remove leading and trailing empty lines.
5215 #
5216 asLines = self.sComment.split('\n');
5217 for iLine, sLine in enumerate(asLines):
5218 asLines[iLine] = sLine.lstrip().lstrip('*').lstrip();
5219
5220 while asLines and not asLines[0]:
5221 self.iCommentLine += 1;
5222 asLines.pop(0);
5223
5224 while asLines and not asLines[-1]:
5225 asLines.pop(len(asLines) - 1);
5226
5227 #
5228 # Check for old style: Opcode 0x0f 0x12
5229 #
5230 if asLines[0].startswith('Opcode '):
5231 self.parseCommentOldOpcode(asLines);
5232
5233 #
5234 # Look for @op* tagged data.
5235 #
5236 cOpTags = 0;
5237 sFlatDefault = None;
5238 sCurTag = '@default';
5239 iCurTagLine = 0;
5240 asCurSection = [];
5241 aasSections = [ asCurSection, ];
5242 for iLine, sLine in enumerate(asLines):
5243 if not sLine.startswith('@'):
5244 if sLine:
5245 asCurSection.append(sLine);
5246 elif asCurSection:
5247 asCurSection = [];
5248 aasSections.append(asCurSection);
5249 else:
5250 #
5251 # Process the previous tag.
5252 #
5253 if not asCurSection and len(aasSections) > 1:
5254 aasSections.pop(-1);
5255 if sCurTag in self.dTagHandlers:
5256 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
5257 cOpTags += 1;
5258 elif sCurTag.startswith('@op'):
5259 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
5260 elif sCurTag == '@default':
5261 sFlatDefault = self.flattenAllSections(aasSections);
5262 elif '@op' + sCurTag[1:] in self.dTagHandlers:
5263 self.errorComment(iCurTagLine, 'Did you mean "@op%s" rather than "%s"?' % (sCurTag[1:], sCurTag));
5264 elif sCurTag in ['@encoding', '@opencoding']:
5265 self.errorComment(iCurTagLine, 'Did you mean "@openc" rather than "%s"?' % (sCurTag,));
5266
5267 #
5268 # New tag.
5269 #
5270 asSplit = sLine.split(None, 1);
5271 sCurTag = asSplit[0].lower();
5272 if len(asSplit) > 1:
5273 asCurSection = [asSplit[1],];
5274 else:
5275 asCurSection = [];
5276 aasSections = [asCurSection, ];
5277 iCurTagLine = iLine;
5278
5279 #
5280 # Process the final tag.
5281 #
5282 if not asCurSection and len(aasSections) > 1:
5283 aasSections.pop(-1);
5284 if sCurTag in self.dTagHandlers:
5285 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
5286 cOpTags += 1;
5287 elif sCurTag.startswith('@op'):
5288 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
5289 elif sCurTag == '@default':
5290 sFlatDefault = self.flattenAllSections(aasSections);
5291
5292 #
5293 # Don't allow default text in blocks containing @op*.
5294 #
5295 if cOpTags > 0 and sFlatDefault:
5296 self.errorComment(0, 'Untagged comment text is not allowed with @op*: %s' % (sFlatDefault,));
5297
5298 return True;
5299
5300 def parseMacroInvocation(self, sInvocation, offStartInvocation = 0):
5301 """
5302 Parses a macro invocation.
5303
5304 Returns three values:
5305 1. A list of macro arguments, where the zero'th is the macro name.
5306 2. The offset following the macro invocation, into sInvocation of
5307 this is on the same line or into the last line if it is on a
5308 different line.
5309 3. Number of additional lines the invocation spans (i.e. zero if
5310 it is all contained within sInvocation).
5311 """
5312 # First the name.
5313 offOpen = sInvocation.find('(', offStartInvocation);
5314 if offOpen <= offStartInvocation:
5315 self.raiseError("macro invocation open parenthesis not found");
5316 sName = sInvocation[offStartInvocation:offOpen].strip();
5317 if not self.oReMacroName.match(sName):
5318 self.raiseError("invalid macro name '%s'" % (sName,));
5319 asRet = [sName, ];
5320
5321 # Arguments.
5322 iLine = self.iLine;
5323 cDepth = 1;
5324 off = offOpen + 1;
5325 offStart = off;
5326 offCurLn = 0;
5327 chQuote = None;
5328 while cDepth > 0:
5329 if off >= len(sInvocation):
5330 if iLine >= len(self.asLines):
5331 self.error('macro invocation beyond end of file');
5332 return (asRet, off - offCurLn, iLine - self.iLine);
5333 offCurLn = off;
5334 sInvocation += self.asLines[iLine];
5335 iLine += 1;
5336 ch = sInvocation[off];
5337
5338 if chQuote:
5339 if ch == '\\' and off + 1 < len(sInvocation):
5340 off += 1;
5341 elif ch == chQuote:
5342 chQuote = None;
5343 elif ch in ('"', '\'',):
5344 chQuote = ch;
5345 elif ch in (',', ')',):
5346 if cDepth == 1:
5347 asRet.append(sInvocation[offStart:off].strip());
5348 offStart = off + 1;
5349 if ch == ')':
5350 cDepth -= 1;
5351 elif ch == '(':
5352 cDepth += 1;
5353 off += 1;
5354
5355 return (asRet, off - offCurLn, iLine - self.iLine);
5356
5357 def findAndParseMacroInvocationEx(self, sCode, sMacro, offStart = 0):
5358 """
5359 Returns (None, len(sCode), 0) if not found, otherwise the
5360 parseMacroInvocation() return value.
5361 """
5362 offHit = sCode.find(sMacro, offStart);
5363 if offHit >= 0 and sCode[offHit + len(sMacro):].strip()[0] == '(':
5364 return self.parseMacroInvocation(sCode, offHit);
5365 return (None, len(sCode), 0);
5366
5367 def findAndParseMacroInvocation(self, sCode, sMacro):
5368 """
5369 Returns None if not found, arguments as per parseMacroInvocation if found.
5370 """
5371 return self.findAndParseMacroInvocationEx(sCode, sMacro)[0];
5372
5373 def findAndParseFirstMacroInvocation(self, sCode, asMacro):
5374 """
5375 Returns same as findAndParseMacroInvocation.
5376 """
5377 for sMacro in asMacro:
5378 asRet = self.findAndParseMacroInvocation(sCode, sMacro);
5379 if asRet is not None:
5380 return asRet;
5381 return None;
5382
5383 def workerIemOpMnemonicEx(self, sMacro, sStats, sAsm, sForm, sUpper, sLower, # pylint: disable=too-many-arguments
5384 sDisHints, sIemHints, asOperands):
5385 """
5386 Processes one of the a IEMOP_MNEMONIC0EX, IEMOP_MNEMONIC1EX, IEMOP_MNEMONIC2EX,
5387 IEMOP_MNEMONIC3EX, and IEMOP_MNEMONIC4EX macros.
5388 """
5389 #
5390 # Some invocation checks.
5391 #
5392 if sUpper != sUpper.upper():
5393 self.error('%s: bad a_Upper parameter: %s' % (sMacro, sUpper,));
5394 if sLower != sLower.lower():
5395 self.error('%s: bad a_Lower parameter: %s' % (sMacro, sLower,));
5396 if sUpper.lower() != sLower:
5397 self.error('%s: a_Upper and a_Lower parameters does not match: %s vs %s' % (sMacro, sUpper, sLower,));
5398 if not self.oReMnemonic.match(sLower):
5399 self.error('%s: invalid a_Lower: %s (valid: %s)' % (sMacro, sLower, self.oReMnemonic.pattern,));
5400
5401 #
5402 # Check if sIemHints tells us to not consider this macro invocation.
5403 #
5404 if sIemHints.find('IEMOPHINT_SKIP_PYTHON') >= 0:
5405 return True;
5406
5407 # Apply to the last instruction only for now.
5408 if not self.aoCurInstrs:
5409 self.addInstruction();
5410 oInstr = self.aoCurInstrs[-1];
5411 if oInstr.iLineMnemonicMacro == -1:
5412 oInstr.iLineMnemonicMacro = self.iLine;
5413 else:
5414 self.error('%s: already saw a IEMOP_MNEMONIC* macro on line %u for this instruction'
5415 % (sMacro, oInstr.iLineMnemonicMacro,));
5416
5417 # Mnemonic
5418 if oInstr.sMnemonic is None:
5419 oInstr.sMnemonic = sLower;
5420 elif oInstr.sMnemonic != sLower:
5421 self.error('%s: current instruction and a_Lower does not match: %s vs %s' % (sMacro, oInstr.sMnemonic, sLower,));
5422
5423 # Process operands.
5424 if len(oInstr.aoOperands) not in [0, len(asOperands)]:
5425 self.error('%s: number of operands given by @opN does not match macro: %s vs %s'
5426 % (sMacro, len(oInstr.aoOperands), len(asOperands),));
5427 for iOperand, sType in enumerate(asOperands):
5428 sWhere = g_kdOpTypes.get(sType, [None, None])[1];
5429 if sWhere is None:
5430 self.error('%s: unknown a_Op%u value: %s' % (sMacro, iOperand + 1, sType));
5431 if iOperand < len(oInstr.aoOperands): # error recovery.
5432 sWhere = oInstr.aoOperands[iOperand].sWhere;
5433 sType = oInstr.aoOperands[iOperand].sType;
5434 else:
5435 sWhere = 'reg';
5436 sType = 'Gb';
5437 if iOperand == len(oInstr.aoOperands):
5438 oInstr.aoOperands.append(Operand(sWhere, sType))
5439 elif oInstr.aoOperands[iOperand].sWhere != sWhere or oInstr.aoOperands[iOperand].sType != sType:
5440 self.error('%s: @op%u and a_Op%u mismatch: %s:%s vs %s:%s'
5441 % (sMacro, iOperand + 1, iOperand + 1, oInstr.aoOperands[iOperand].sWhere,
5442 oInstr.aoOperands[iOperand].sType, sWhere, sType,));
5443
5444 # Encoding.
5445 if sForm not in g_kdIemForms:
5446 self.error('%s: unknown a_Form value: %s' % (sMacro, sForm,));
5447 else:
5448 if oInstr.sEncoding is None:
5449 oInstr.sEncoding = g_kdIemForms[sForm][0];
5450 elif g_kdIemForms[sForm][0] != oInstr.sEncoding:
5451 self.error('%s: current instruction @openc and a_Form does not match: %s vs %s (%s)'
5452 % (sMacro, oInstr.sEncoding, g_kdIemForms[sForm], sForm));
5453
5454 # Check the parameter locations for the encoding.
5455 if g_kdIemForms[sForm][1] is not None:
5456 if len(g_kdIemForms[sForm][1]) > len(oInstr.aoOperands):
5457 self.error('%s: The a_Form=%s has a different operand count: %s (form) vs %s'
5458 % (sMacro, sForm, len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands) ));
5459 else:
5460 for iOperand, sWhere in enumerate(g_kdIemForms[sForm][1]):
5461 if oInstr.aoOperands[iOperand].sWhere != sWhere:
5462 self.error('%s: current instruction @op%u and a_Form location does not match: %s vs %s (%s)'
5463 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sWhere, sWhere, sForm,));
5464 sOpFormMatch = g_kdOpTypes[oInstr.aoOperands[iOperand].sType][4];
5465 if (sOpFormMatch in [ 'REG', 'MEM', ] and sForm.find('_' + sOpFormMatch) < 0) \
5466 or (sOpFormMatch in [ 'FIXED', ] and sForm.find(sOpFormMatch) < 0) \
5467 or (sOpFormMatch == 'RM' and (sForm.find('_MEM') > 0 or sForm.find('_REG') > 0) ) \
5468 or (sOpFormMatch == 'V' and ( not (sForm.find('VEX') > 0 or sForm.find('XOP')) \
5469 or sForm.replace('VEX','').find('V') < 0) ):
5470 self.error('%s: current instruction @op%u and a_Form type does not match: %s/%s vs %s'
5471 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sType, sOpFormMatch, sForm, ));
5472 if len(g_kdIemForms[sForm][1]) < len(oInstr.aoOperands):
5473 for iOperand in range(len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands)):
5474 if oInstr.aoOperands[iOperand].sType != 'FIXED' \
5475 and g_kdOpTypes[oInstr.aoOperands[iOperand].sType][0] != 'IDX_ParseFixedReg':
5476 self.error('%s: Expected FIXED type operand #%u following operands given by a_Form=%s: %s (%s)'
5477 % (sMacro, iOperand, sForm, oInstr.aoOperands[iOperand].sType,
5478 oInstr.aoOperands[iOperand].sWhere));
5479
5480
5481 # Check @opcodesub
5482 if oInstr.sSubOpcode \
5483 and g_kdIemForms[sForm][2] \
5484 and oInstr.sSubOpcode.find(g_kdIemForms[sForm][2]) < 0:
5485 self.error('%s: current instruction @opcodesub and a_Form does not match: %s vs %s (%s)'
5486 % (sMacro, oInstr.sSubOpcode, g_kdIemForms[sForm][2], sForm,));
5487
5488 # Stats.
5489 if not self.oReStatsName.match(sStats):
5490 self.error('%s: invalid a_Stats value: %s' % (sMacro, sStats,));
5491 elif oInstr.sStats is None:
5492 oInstr.sStats = sStats;
5493 elif oInstr.sStats != sStats:
5494 self.error('%s: mismatching @opstats and a_Stats value: %s vs %s'
5495 % (sMacro, oInstr.sStats, sStats,));
5496
5497 # Process the hints (simply merge with @ophints w/o checking anything).
5498 for sHint in sDisHints.split('|'):
5499 sHint = sHint.strip();
5500 if sHint.startswith('DISOPTYPE_'):
5501 sShortHint = sHint[len('DISOPTYPE_'):].lower();
5502 if sShortHint in g_kdHints:
5503 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5504 else:
5505 self.error('%s: unknown a_fDisHints value: %s' % (sMacro, sHint,));
5506 elif sHint != '0':
5507 self.error('%s: expected a_fDisHints value: %s' % (sMacro, sHint,));
5508
5509 for sHint in sIemHints.split('|'):
5510 sHint = sHint.strip();
5511 if sHint.startswith('IEMOPHINT_'):
5512 sShortHint = sHint[len('IEMOPHINT_'):].lower();
5513 if sShortHint in g_kdHints:
5514 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5515 else:
5516 self.error('%s: unknown a_fIemHints value: %s' % (sMacro, sHint,));
5517 elif sHint != '0':
5518 self.error('%s: expected a_fIemHints value: %s' % (sMacro, sHint,));
5519
5520 _ = sAsm;
5521 return True;
5522
5523 def workerIemOpMnemonic(self, sMacro, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands):
5524 """
5525 Processes one of the a IEMOP_MNEMONIC0, IEMOP_MNEMONIC1, IEMOP_MNEMONIC2,
5526 IEMOP_MNEMONIC3, and IEMOP_MNEMONIC4 macros.
5527 """
5528 if not asOperands:
5529 return self.workerIemOpMnemonicEx(sMacro, sLower, sLower, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5530 return self.workerIemOpMnemonicEx(sMacro, sLower + '_' + '_'.join(asOperands), sLower + ' ' + ','.join(asOperands),
5531 sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5532
5533 def workerIemMcBegin(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine):
5534 """
5535 Process a IEM_MC_BEGIN macro invocation.
5536 """
5537 if self.fDebugMc:
5538 self.debug('IEM_MC_BEGIN on %s off %s' % (self.iLine, offBeginStatementInLine,));
5539 #self.debug('%s<eos>' % (sCode,));
5540
5541 # Check preconditions.
5542 if not self.oCurFunction:
5543 self.raiseError('IEM_MC_BEGIN w/o current function (%s)' % (sCode,));
5544 if self.oCurMcBlock:
5545 self.raiseError('IEM_MC_BEGIN before IEM_MC_END. Previous IEM_MC_BEGIN at line %u' % (self.oCurMcBlock.iBeginLine,));
5546
5547 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5548 cchIndent = offBeginStatementInCodeStr;
5549 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5550 if offPrevNewline >= 0:
5551 cchIndent -= offPrevNewline + 1;
5552 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5553
5554 # Start a new block.
5555 # But don't add it to the list unless the context matches the host architecture.
5556 self.oCurMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine, self.oCurFunction, self.iMcBlockInFunc,
5557 oInstruction = self.aoCurInstrs[-1] if self.aoCurInstrs else None,
5558 cchIndent = cchIndent);
5559 try:
5560 if ( not self.aoCppCondStack
5561 or not self.sHostArch
5562 or self.PreprocessorConditional.isInBlockForArch(self.aoCppCondStack, self.sHostArch, self.iLine)):
5563 g_aoMcBlocks.append(self.oCurMcBlock);
5564 self.cTotalMcBlocks += 1;
5565 except Exception as oXcpt:
5566 self.raiseError(oXcpt.args[0]);
5567
5568 if self.oCurMcBlock.oInstruction:
5569 self.oCurMcBlock.oInstruction.aoMcBlocks.append(self.oCurMcBlock);
5570 self.iMcBlockInFunc += 1;
5571 return True;
5572
5573 @staticmethod
5574 def extractLinesFromMacroExpansionLine(sRawLine, offBegin, offEnd, sBeginStmt = 'IEM_MC_BEGIN'):
5575 """
5576 Helper used by workerIemMcEnd and workerIemMcDeferToCImplXRet for
5577 extracting a statement block from a string that's the result of macro
5578 expansion and therefore contains multiple "sub-lines" as it were.
5579
5580 Returns list of lines covering offBegin thru offEnd in sRawLine.
5581 """
5582
5583 off = sRawLine.find('\n', offEnd);
5584 if off > 0:
5585 sRawLine = sRawLine[:off + 1];
5586
5587 off = sRawLine.rfind('\n', 0, offBegin) + 1;
5588 sRawLine = sRawLine[off:];
5589 if not sRawLine.strip().startswith(sBeginStmt):
5590 sRawLine = sRawLine[offBegin - off:]
5591
5592 return [sLine + '\n' for sLine in sRawLine.split('\n')];
5593
5594 def workerIemMcEnd(self, offEndStatementInLine):
5595 """
5596 Process a IEM_MC_END macro invocation.
5597 """
5598 if self.fDebugMc:
5599 self.debug('IEM_MC_END on %s off %s' % (self.iLine, offEndStatementInLine,));
5600
5601 # Check preconditions.
5602 if not self.oCurMcBlock:
5603 self.raiseError('IEM_MC_END w/o IEM_MC_BEGIN.');
5604
5605 #
5606 # HACK ALERT! For blocks originating from macro expansion the start and
5607 # end line will be the same, but the line has multiple
5608 # newlines inside it. So, we have to do some extra tricks
5609 # to get the lines out of there. We ASSUME macros aren't
5610 # messy, but keep IEM_MC_BEGIN/END on separate lines.
5611 #
5612 if self.iLine > self.oCurMcBlock.iBeginLine:
5613 asLines = self.asLines[self.oCurMcBlock.iBeginLine - 1 : self.iLine];
5614 if not asLines[0].strip().startswith('IEM_MC_BEGIN'):
5615 self.raiseError('IEM_MC_BEGIN is not the first word on the line');
5616
5617 # Hack alert! Detect mixed tail/head macros a la cmpxchg16b and split up the lines
5618 # so we can deal correctly with IEM_MC_END below and everything else.
5619 for sLine in asLines:
5620 cNewLines = sLine.count('\n');
5621 assert cNewLines > 0;
5622 if cNewLines > 1:
5623 asLines = self.extractLinesFromMacroExpansionLine(''.join(asLines),
5624 self.oCurMcBlock.offBeginLine,
5625 offEndStatementInLine
5626 + sum(len(s) for s in asLines)
5627 - len(asLines[-1]));
5628 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Partial;
5629 break;
5630 else:
5631 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Entire;
5632 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1],
5633 self.oCurMcBlock.offBeginLine, offEndStatementInLine);
5634
5635 #
5636 # Strip anything following the IEM_MC_END(); statement in the final line,
5637 # so that we don't carry on any trailing 'break' after macro expansions
5638 # like for iemOp_movsb_Xb_Yb.
5639 #
5640 while asLines[-1].strip() == '':
5641 asLines.pop();
5642 sFinal = asLines[-1];
5643 offFinalEnd = sFinal.find('IEM_MC_END');
5644 offEndInFinal = offFinalEnd;
5645 if offFinalEnd < 0: self.raiseError('bogus IEM_MC_END: Not in final line: %s' % (sFinal,));
5646 offFinalEnd += len('IEM_MC_END');
5647
5648 while sFinal[offFinalEnd].isspace():
5649 offFinalEnd += 1;
5650 if sFinal[offFinalEnd] != '(': self.raiseError('bogus IEM_MC_END: Expected "(" at %s: %s' % (offFinalEnd, sFinal,));
5651 offFinalEnd += 1;
5652
5653 while sFinal[offFinalEnd].isspace():
5654 offFinalEnd += 1;
5655 if sFinal[offFinalEnd] != ')': self.raiseError('bogus IEM_MC_END: Expected ")" at %s: %s' % (offFinalEnd, sFinal,));
5656 offFinalEnd += 1;
5657
5658 while sFinal[offFinalEnd].isspace():
5659 offFinalEnd += 1;
5660 if sFinal[offFinalEnd] != ';': self.raiseError('bogus IEM_MC_END: Expected ";" at %s: %s' % (offFinalEnd, sFinal,));
5661 offFinalEnd += 1;
5662
5663 asLines[-1] = sFinal[: offFinalEnd];
5664
5665 #
5666 # Complete and discard the current block.
5667 #
5668 self.oCurMcBlock.complete(self.iLine, offEndStatementInLine,
5669 offEndStatementInLine + offFinalEnd - offEndInFinal, asLines);
5670 self.oCurMcBlock = None;
5671 return True;
5672
5673 def workerIemMcDeferToCImplXRet(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine, cParams):
5674 """
5675 Process a IEM_MC_DEFER_TO_CIMPL_[1-5]_RET macro invocation.
5676 """
5677 sStmt = 'IEM_MC_DEFER_TO_CIMPL_%d_RET' % (cParams,);
5678 if self.fDebugMc:
5679 self.debug('%s on %s off %s' % (sStmt, self.iLine, offBeginStatementInLine,));
5680 #self.debug('%s<eos>' % (sCode,));
5681
5682 # Check preconditions.
5683 if not self.oCurFunction:
5684 self.raiseError('%s w/o current function (%s)' % (sStmt, sCode,));
5685 if self.oCurMcBlock:
5686 self.raiseError('%s inside IEM_MC_BEGIN block starting at line %u' % (sStmt, self.oCurMcBlock.iBeginLine,));
5687
5688 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5689 cchIndent = offBeginStatementInCodeStr;
5690 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5691 if offPrevNewline >= 0:
5692 cchIndent -= offPrevNewline + 1;
5693 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5694
5695 # Start a new block.
5696 oMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine, self.oCurFunction, self.iMcBlockInFunc,
5697 oInstruction = self.aoCurInstrs[-1] if self.aoCurInstrs else None,
5698 cchIndent = cchIndent, fDeferToCImpl = True);
5699
5700 # Parse the statment.
5701 asArgs, offAfter, cLines = self.findAndParseMacroInvocationEx(sCode, sStmt, offBeginStatementInCodeStr);
5702 if asArgs is None:
5703 self.raiseError('%s: Closing parenthesis not found!' % (sStmt,));
5704 if len(asArgs) != cParams + 4:
5705 self.raiseError('%s: findAndParseMacroInvocationEx returns %s args, expected %s! (%s)'
5706 % (sStmt, len(asArgs), cParams + 4, asArgs));
5707
5708 oMcBlock.aoStmts = [ McBlock.parseMcDeferToCImpl(oMcBlock, asArgs[0], asArgs[1:]), ];
5709
5710 # These MCs are not typically part of macro expansions, but let's get
5711 # it out of the way immediately if it's the case.
5712 if cLines > 0 or self.asLines[oMcBlock.iBeginLine - 1].count('\n') <= 1:
5713 asLines = self.asLines[self.iLine - 1 : self.iLine - 1 + cLines + 1];
5714 assert offAfter < len(asLines[-1]) and asLines[-1][offAfter] == ';', \
5715 'iBeginLine=%d iLine=%d offAfter=%s line: "%s"' % (oMcBlock.iBeginLine, self.iLine, offAfter, asLines[-1],);
5716 asLines[-1] = asLines[-1][:offAfter + 1];
5717 else:
5718 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1], offBeginStatementInCodeStr,
5719 offAfter, sStmt);
5720 assert asLines[-1].find(';') >= 0;
5721 asLines[-1] = asLines[-1][:asLines[-1].find(';') + 1];
5722
5723 assert asLines[0].find(sStmt) >= 0;
5724 #if not asLines[0].strip().startswith(sStmt):
5725 # self.raiseError('%s is not the first word on the line: %s' % (sStmt, asLines[0].strip()));
5726
5727 # Advance to the line with the closing ')'.
5728 self.iLine += cLines;
5729
5730 # Complete the block.
5731 oMcBlock.complete(self.iLine, 0 if cLines > 0 else offBeginStatementInCodeStr, offAfter + 1, asLines);
5732
5733 g_aoMcBlocks.append(oMcBlock);
5734 if oMcBlock.oInstruction:
5735 oMcBlock.oInstruction.aoMcBlocks.append(oMcBlock);
5736 self.cTotalMcBlocks += 1;
5737 self.iMcBlockInFunc += 1;
5738
5739 return True;
5740
5741 def workerStartFunction(self, asArgs):
5742 """
5743 Deals with the start of a decoder function.
5744
5745 These are all defined using one of the FNIEMOP*_DEF* and FNIEMOP_*STUB*
5746 macros, so we get a argument list for these where the 0th argument is the
5747 macro name.
5748 """
5749 # Complete any existing function.
5750 if self.oCurFunction:
5751 self.oCurFunction.complete(self.iLine - 1, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine - 1]);
5752
5753 # Create the new function.
5754 self.oCurFunction = DecoderFunction(self.sSrcFile, self.iLine, asArgs[1], asArgs);
5755 return True;
5756
5757 def checkCodeForMacro(self, sCode, offLine):
5758 """
5759 Checks code for relevant macro invocation.
5760 """
5761
5762 #
5763 # Scan macro invocations.
5764 #
5765 if sCode.find('(') > 0:
5766 # Look for instruction decoder function definitions. ASSUME single line.
5767 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5768 [ 'FNIEMOP_DEF',
5769 'FNIEMOPRM_DEF',
5770 'FNIEMOP_STUB',
5771 'FNIEMOP_STUB_1',
5772 'FNIEMOP_UD_STUB',
5773 'FNIEMOP_UD_STUB_1' ]);
5774 if asArgs is not None:
5775 self.workerStartFunction(asArgs);
5776 #self.debug('%s: oCurFunction=%s' % (self.iLine, self.oCurFunction.sName,));
5777
5778 if not self.aoCurInstrs:
5779 self.addInstruction();
5780 for oInstr in self.aoCurInstrs:
5781 if oInstr.iLineFnIemOpMacro == -1:
5782 oInstr.iLineFnIemOpMacro = self.iLine;
5783 else:
5784 self.error('%s: already seen a FNIEMOP_XXX macro for %s' % (asArgs[0], oInstr,) );
5785 self.setInstrunctionAttrib('sFunction', asArgs[1]);
5786 self.setInstrunctionAttrib('fStub', asArgs[0].find('STUB') > 0, fOverwrite = True);
5787 self.setInstrunctionAttrib('fUdStub', asArgs[0].find('UD_STUB') > 0, fOverwrite = True);
5788 if asArgs[0].find('STUB') > 0:
5789 self.doneInstructions(fEndOfFunction = True);
5790 return True;
5791
5792 # Check for worker function definitions, so we can get a context for MC blocks.
5793 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5794 [ 'FNIEMOP_DEF_1',
5795 'FNIEMOP_DEF_2', ]);
5796 if asArgs is not None:
5797 self.workerStartFunction(asArgs);
5798 #self.debug('%s: oCurFunction=%s (%s)' % (self.iLine, self.oCurFunction.sName, asArgs[0]));
5799 return True;
5800
5801 # IEMOP_HLP_DONE_VEX_DECODING_*
5802 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5803 [ 'IEMOP_HLP_DONE_VEX_DECODING',
5804 'IEMOP_HLP_DONE_VEX_DECODING_L0',
5805 'IEMOP_HLP_DONE_VEX_DECODING_NO_VVVV',
5806 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV',
5807 ]);
5808 if asArgs is not None:
5809 sMacro = asArgs[0];
5810 if sMacro in ('IEMOP_HLP_DONE_VEX_DECODING_L0', 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV', ):
5811 for oInstr in self.aoCurInstrs:
5812 if 'vex_l_zero' not in oInstr.dHints:
5813 if oInstr.iLineMnemonicMacro >= 0:
5814 self.errorOnLine(oInstr.iLineMnemonicMacro,
5815 'Missing IEMOPHINT_VEX_L_ZERO! (%s on line %d)' % (sMacro, self.iLine,));
5816 oInstr.dHints['vex_l_zero'] = True;
5817
5818 #
5819 # IEMOP_MNEMONIC*
5820 #
5821 if sCode.find('IEMOP_MNEMONIC') >= 0:
5822 # IEMOP_MNEMONIC(a_Stats, a_szMnemonic) IEMOP_INC_STATS(a_Stats)
5823 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC');
5824 if asArgs is not None:
5825 if len(self.aoCurInstrs) == 1:
5826 oInstr = self.aoCurInstrs[0];
5827 if oInstr.sStats is None:
5828 oInstr.sStats = asArgs[1];
5829 self.deriveMnemonicAndOperandsFromStats(oInstr, asArgs[1]);
5830
5831 # IEMOP_MNEMONIC0EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5832 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0EX');
5833 if asArgs is not None:
5834 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[6],
5835 asArgs[7], []);
5836 # IEMOP_MNEMONIC1EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5837 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1EX');
5838 if asArgs is not None:
5839 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[7],
5840 asArgs[8], [asArgs[6],]);
5841 # IEMOP_MNEMONIC2EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5842 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2EX');
5843 if asArgs is not None:
5844 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[8],
5845 asArgs[9], [asArgs[6], asArgs[7]]);
5846 # IEMOP_MNEMONIC3EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints,
5847 # a_fIemHints)
5848 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3EX');
5849 if asArgs is not None:
5850 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[9],
5851 asArgs[10], [asArgs[6], asArgs[7], asArgs[8],]);
5852 # IEMOP_MNEMONIC4EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints,
5853 # a_fIemHints)
5854 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4EX');
5855 if asArgs is not None:
5856 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[10],
5857 asArgs[11], [asArgs[6], asArgs[7], asArgs[8], asArgs[9],]);
5858
5859 # IEMOP_MNEMONIC0(a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5860 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0');
5861 if asArgs is not None:
5862 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], []);
5863 # IEMOP_MNEMONIC1(a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5864 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1');
5865 if asArgs is not None:
5866 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[5], asArgs[6], [asArgs[4],]);
5867 # IEMOP_MNEMONIC2(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5868 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2');
5869 if asArgs is not None:
5870 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[6], asArgs[7],
5871 [asArgs[4], asArgs[5],]);
5872 # IEMOP_MNEMONIC3(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints, a_fIemHints)
5873 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3');
5874 if asArgs is not None:
5875 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[7], asArgs[8],
5876 [asArgs[4], asArgs[5], asArgs[6],]);
5877 # IEMOP_MNEMONIC4(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints, a_fIemHints)
5878 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4');
5879 if asArgs is not None:
5880 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[8], asArgs[9],
5881 [asArgs[4], asArgs[5], asArgs[6], asArgs[7],]);
5882
5883 #
5884 # IEM_MC_BEGIN + IEM_MC_END.
5885 # We must support multiple instances per code snippet.
5886 #
5887 offCode = sCode.find('IEM_MC_');
5888 if offCode >= 0:
5889 for oMatch in self.oReMcBeginEnd.finditer(sCode, offCode):
5890 if oMatch.group(1) == 'END':
5891 self.workerIemMcEnd(offLine + oMatch.start());
5892 elif oMatch.group(1) == 'BEGIN':
5893 self.workerIemMcBegin(sCode, oMatch.start(), offLine + oMatch.start());
5894 else:
5895 self.workerIemMcDeferToCImplXRet(sCode, oMatch.start(), offLine + oMatch.start(),
5896 int(oMatch.group(1)[len('DEFER_TO_CIMPL_')]));
5897 return True;
5898
5899 return False;
5900
5901 def workerPreprocessorRecreateMacroRegex(self):
5902 """
5903 Recreates self.oReMacros when self.dMacros changes.
5904 """
5905 if self.dMacros:
5906 sRegex = '';
5907 for sName, oMacro in self.dMacros.items():
5908 if sRegex:
5909 sRegex += r'|' + sName;
5910 else:
5911 sRegex = r'\b(' + sName;
5912 if oMacro.asArgs is not None:
5913 sRegex += r'\s*\(';
5914 else:
5915 sRegex += r'\b';
5916 sRegex += ')';
5917 self.oReMacros = re.compile(sRegex);
5918 else:
5919 self.oReMacros = None;
5920 return True;
5921
5922 def workerPreprocessorDefine(self, sRest):
5923 """
5924 Handles a macro #define, the sRest is what follows after the directive word.
5925 """
5926 assert sRest[-1] == '\n';
5927
5928 #
5929 # If using line continutation, just concat all the lines together,
5930 # preserving the newline character but not the escaping.
5931 #
5932 iLineStart = self.iLine;
5933 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
5934 sRest = sRest[0:-2].rstrip() + '\n' + self.asLines[self.iLine];
5935 self.iLine += 1;
5936 #self.debug('workerPreprocessorDefine: sRest=%s<EOS>' % (sRest,));
5937
5938 #
5939 # Use regex to split out the name, argument list and body.
5940 # If this fails, we assume it's a simple macro.
5941 #
5942 oMatch = self.oReHashDefine2.match(sRest);
5943 if oMatch:
5944 sAllArgs = oMatch.group(2).strip();
5945 asArgs = [sParam.strip() for sParam in sAllArgs.split(',')] if sAllArgs else None;
5946 sBody = oMatch.group(3);
5947 else:
5948 oMatch = self.oReHashDefine3.match(sRest);
5949 if not oMatch:
5950 self.debug('workerPreprocessorDefine: wtf? sRest=%s' % (sRest,));
5951 return self.error('bogus macro definition: %s' % (sRest,));
5952 asArgs = None;
5953 sBody = oMatch.group(2);
5954 sName = oMatch.group(1);
5955 assert sName == sName.strip();
5956 #self.debug('workerPreprocessorDefine: sName=%s asArgs=%s sBody=%s<EOS>' % (sName, asArgs, sBody));
5957
5958 #
5959 # Is this of any interest to us? We do NOT support MC blocks wihtin
5960 # nested macro expansion, just to avoid lots of extra work.
5961 #
5962 # There is only limited support for macros expanding to partial MC blocks.
5963 #
5964 # Note! IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX and other macros someone making
5965 # use of IEMOP_RAISE_INVALID_LOCK_PREFIX_RET() will be ignored here and
5966 # dealt with by overriding IEMOP_RAISE_INVALID_LOCK_PREFIX_RET and its
5967 # siblings in the recompiler. This is a lot simpler than nested macro
5968 # expansion and lots of heuristics for locating all the relevant macros.
5969 # Also, this way we don't produce lots of unnecessary threaded functions.
5970 #
5971 if sBody.find("IEM_MC_BEGIN") < 0 and sBody.find("IEM_MC_END") < 0:
5972 #self.debug('workerPreprocessorDefine: irrelevant (%s: %s)' % (sName, sBody));
5973 return True;
5974
5975 #
5976 # Add the macro.
5977 #
5978 if self.fDebugPreproc:
5979 self.debug('#define %s on line %u' % (sName, self.iLine,));
5980 self.dMacros[sName] = SimpleParser.Macro(sName, asArgs, sBody.strip(), iLineStart);
5981 return self.workerPreprocessorRecreateMacroRegex();
5982
5983 def workerPreprocessorUndef(self, sRest):
5984 """
5985 Handles a macro #undef, the sRest is what follows after the directive word.
5986 """
5987 # Quick comment strip and isolate the name.
5988 offSlash = sRest.find('/');
5989 if offSlash > 0:
5990 sRest = sRest[:offSlash];
5991 sName = sRest.strip();
5992
5993 # Remove the macro if we're clocking it.
5994 if sName in self.dMacros:
5995 if self.fDebugPreproc:
5996 self.debug('#undef %s on line %u' % (sName, self.iLine,));
5997 del self.dMacros[sName];
5998 return self.workerPreprocessorRecreateMacroRegex();
5999
6000 return True;
6001
6002 def workerPreprocessorIfOrElif(self, sDirective, sRest):
6003 """
6004 Handles an #if, #ifdef, #ifndef or #elif directive.
6005 """
6006 #
6007 # Sanity check #elif.
6008 #
6009 if sDirective == 'elif':
6010 if len(self.aoCppCondStack) == 0:
6011 self.raiseError('#elif without #if');
6012 if self.aoCppCondStack[-1].fInElse:
6013 self.raiseError('#elif after #else');
6014
6015 #
6016 # If using line continutation, just concat all the lines together,
6017 # stripping both the newline and escape characters.
6018 #
6019 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
6020 sRest = sRest[0:-2].rstrip() + ' ' + self.asLines[self.iLine];
6021 self.iLine += 1;
6022
6023 # Strip it of all comments and leading and trailing blanks.
6024 sRest = self.stripComments(sRest).strip();
6025
6026 #
6027 # Stash it.
6028 #
6029 try:
6030 oPreprocCond = self.PreprocessorConditional(sDirective, sRest);
6031 except Exception as oXcpt:
6032 self.raiseError(oXcpt.args[0]);
6033
6034 if sDirective == 'elif':
6035 self.aoCppCondStack[-1].aoElif.append(oPreprocCond);
6036 else:
6037 self.aoCppCondStack.append(oPreprocCond);
6038
6039 return True;
6040
6041 def workerPreprocessorElse(self):
6042 """
6043 Handles an #else directive.
6044 """
6045 if len(self.aoCppCondStack) == 0:
6046 self.raiseError('#else without #if');
6047 if self.aoCppCondStack[-1].fInElse:
6048 self.raiseError('Another #else after #else');
6049
6050 self.aoCppCondStack[-1].fInElse = True;
6051 return True;
6052
6053 def workerPreprocessorEndif(self):
6054 """
6055 Handles an #endif directive.
6056 """
6057 if len(self.aoCppCondStack) == 0:
6058 self.raiseError('#endif without #if');
6059
6060 self.aoCppCondStack.pop();
6061 return True;
6062
6063 def checkPreprocessorDirective(self, sLine):
6064 """
6065 Handles a preprocessor directive.
6066 """
6067 # Skip past the preprocessor hash.
6068 off = sLine.find('#');
6069 assert off >= 0;
6070 off += 1;
6071 while off < len(sLine) and sLine[off].isspace():
6072 off += 1;
6073
6074 # Extract the directive.
6075 offDirective = off;
6076 while off < len(sLine) and not sLine[off].isspace():
6077 off += 1;
6078 sDirective = sLine[offDirective:off];
6079 if self.fDebugPreproc:
6080 self.debug('line %d: #%s...' % (self.iLine, sDirective));
6081
6082 # Skip spaces following it to where the arguments/whatever starts.
6083 while off + 1 < len(sLine) and sLine[off + 1].isspace():
6084 off += 1;
6085 sTail = sLine[off:];
6086
6087 # Handle the directive.
6088 if sDirective == 'define':
6089 return self.workerPreprocessorDefine(sTail);
6090 if sDirective == 'undef':
6091 return self.workerPreprocessorUndef(sTail);
6092 if sDirective in ('if', 'ifdef', 'ifndef', 'elif',):
6093 return self.workerPreprocessorIfOrElif(sDirective, sTail);
6094 if sDirective == 'else':
6095 return self.workerPreprocessorElse();
6096 if sDirective == 'endif':
6097 return self.workerPreprocessorEndif();
6098
6099 if self.fDebugPreproc:
6100 self.debug('line %d: Unknown preprocessor directive: %s' % (self.iLine, sDirective));
6101 return False;
6102
6103 def expandMacros(self, sLine, oMatch):
6104 """
6105 Expands macros we know about in the given line.
6106 Currently we ASSUME there is only one and that is what oMatch matched.
6107 """
6108 #
6109 # Get our bearings.
6110 #
6111 offMatch = oMatch.start();
6112 sName = oMatch.group(1);
6113 assert sName == sLine[oMatch.start() : oMatch.end()];
6114 fWithArgs = sName.endswith('(');
6115 if fWithArgs:
6116 sName = sName[:-1].strip();
6117 oMacro = self.dMacros[sName] # type: SimpleParser.Macro
6118
6119 #
6120 # Deal with simple macro invocations w/o parameters.
6121 #
6122 if not fWithArgs:
6123 if self.fDebugPreproc:
6124 self.debug('expanding simple macro %s on line %u' % (sName, self.iLine,));
6125 return sLine[:offMatch] + oMacro.expandMacro(self) + sLine[oMatch.end():];
6126
6127 #
6128 # Complicated macro with parameters.
6129 # Start by extracting the parameters. ASSUMES they are all on the same line!
6130 #
6131 cLevel = 1;
6132 offCur = oMatch.end();
6133 offCurArg = offCur;
6134 asArgs = [];
6135 while True:
6136 if offCur >= len(sLine):
6137 self.raiseError('expandMacros: Invocation of macro %s spans multiple lines!' % (sName,));
6138 ch = sLine[offCur];
6139 if ch == '(':
6140 cLevel += 1;
6141 elif ch == ')':
6142 cLevel -= 1;
6143 if cLevel == 0:
6144 asArgs.append(sLine[offCurArg:offCur].strip());
6145 break;
6146 elif ch == ',' and cLevel == 1:
6147 asArgs.append(sLine[offCurArg:offCur].strip());
6148 offCurArg = offCur + 1;
6149 offCur += 1;
6150 if len(oMacro.asArgs) == 0 and len(asArgs) == 1 and asArgs[0] == '': # trick for empty parameter list.
6151 asArgs = [];
6152 if len(oMacro.asArgs) != len(asArgs):
6153 self.raiseError('expandMacros: Argument mismatch in %s invocation' % (oMacro.sName,));
6154
6155 #
6156 # Do the expanding.
6157 #
6158 if self.fDebugPreproc:
6159 self.debug('expanding macro %s on line %u with arguments %s' % (sName, self.iLine, asArgs));
6160 return sLine[:offMatch] + oMacro.expandMacro(self, asArgs) + sLine[offCur + 1 :];
6161
6162 def parse(self):
6163 """
6164 Parses the given file.
6165
6166 Returns number or errors.
6167 Raises exception on fatal trouble.
6168 """
6169 #self.debug('Parsing %s' % (self.sSrcFile,));
6170
6171 #
6172 # Loop thru the lines.
6173 #
6174 # Please mind that self.iLine may be updated by checkCodeForMacro and
6175 # other worker methods.
6176 #
6177 while self.iLine < len(self.asLines):
6178 sLine = self.asLines[self.iLine];
6179 self.iLine += 1;
6180 #self.debug('line %u: %s' % (self.iLine, sLine[:-1]));
6181
6182 # Expand macros we know about if we're currently in code.
6183 if self.iState == self.kiCode and self.oReMacros:
6184 oMatch = self.oReMacros.search(sLine);
6185 if oMatch:
6186 sLine = self.expandMacros(sLine, oMatch);
6187 if self.fDebugPreproc:
6188 self.debug('line %d: expanded\n%s ==>\n%s' % (self.iLine, self.asLines[self.iLine - 1], sLine[:-1],));
6189 self.asLines[self.iLine - 1] = sLine;
6190
6191 # Check for preprocessor directives before comments and other stuff.
6192 # ASSUMES preprocessor directives doesn't end with multiline comments.
6193 if self.iState == self.kiCode and sLine.lstrip().startswith('#'):
6194 if self.fDebugPreproc:
6195 self.debug('line %d: preproc' % (self.iLine,));
6196 self.checkPreprocessorDirective(sLine);
6197 else:
6198 # Look for comments.
6199 offSlash = sLine.find('/');
6200 if offSlash >= 0:
6201 if offSlash + 1 >= len(sLine) or sLine[offSlash + 1] != '/' or self.iState != self.kiCode:
6202 offLine = 0;
6203 while offLine < len(sLine):
6204 if self.iState == self.kiCode:
6205 # Look for substantial multiline comment so we pass the following MC as a whole line:
6206 # IEM_MC_ARG_CONST(uint8_t, bImmArg, /*=*/ bImm, 2);
6207 # Note! We ignore C++ comments here, assuming these aren't used in lines with C-style comments.
6208 offHit = sLine.find('/*', offLine);
6209 while offHit >= 0:
6210 offEnd = sLine.find('*/', offHit + 2);
6211 if offEnd < 0 or offEnd - offHit >= 16: # 16 chars is a bit random.
6212 break;
6213 offHit = sLine.find('/*', offEnd);
6214
6215 if offHit >= 0:
6216 self.checkCodeForMacro(sLine[offLine:offHit], offLine);
6217 self.sComment = '';
6218 self.iCommentLine = self.iLine;
6219 self.iState = self.kiCommentMulti;
6220 offLine = offHit + 2;
6221 else:
6222 self.checkCodeForMacro(sLine[offLine:], offLine);
6223 offLine = len(sLine);
6224
6225 elif self.iState == self.kiCommentMulti:
6226 offHit = sLine.find('*/', offLine);
6227 if offHit >= 0:
6228 self.sComment += sLine[offLine:offHit];
6229 self.iState = self.kiCode;
6230 offLine = offHit + 2;
6231 self.parseComment();
6232 else:
6233 self.sComment += sLine[offLine:];
6234 offLine = len(sLine);
6235 else:
6236 assert False;
6237 # C++ line comment.
6238 elif offSlash > 0:
6239 self.checkCodeForMacro(sLine[:offSlash], 0);
6240
6241 # No slash, but append the line if in multi-line comment.
6242 elif self.iState == self.kiCommentMulti:
6243 #self.debug('line %d: multi' % (self.iLine,));
6244 self.sComment += sLine;
6245
6246 # No slash, but check code line for relevant macro.
6247 elif ( self.iState == self.kiCode
6248 and (sLine.find('IEMOP_') >= 0 or sLine.find('FNIEMOPRM_DEF') >= 0 or sLine.find('IEM_MC') >= 0)):
6249 #self.debug('line %d: macro' % (self.iLine,));
6250 self.checkCodeForMacro(sLine, 0);
6251
6252 # If the line is a '}' in the first position, complete the instructions.
6253 elif self.iState == self.kiCode and sLine[0] == '}':
6254 #self.debug('line %d: }' % (self.iLine,));
6255 self.doneInstructions(fEndOfFunction = True);
6256
6257 # Look for instruction table on the form 'IEM_STATIC const PFNIEMOP g_apfnVexMap3'
6258 # so we can check/add @oppfx info from it.
6259 elif self.iState == self.kiCode and sLine.find('PFNIEMOP') > 0 and self.oReFunTable.match(sLine):
6260 self.parseFunctionTable(sLine);
6261
6262 self.doneInstructions(fEndOfFunction = True);
6263 self.debug('%3s%% / %3s stubs out of %4s instructions and %4s MC blocks in %s'
6264 % (self.cTotalStubs * 100 // max(self.cTotalInstr, 1), self.cTotalStubs, self.cTotalInstr,
6265 self.cTotalMcBlocks, os.path.basename(self.sSrcFile),));
6266 return self.printErrors();
6267
6268# Some sanity checking.
6269def __sanityCheckEFlagsClasses():
6270 for sClass, dLists in SimpleParser.kdEFlagsClasses.items():
6271 for sAttrib, asFlags in dLists.items():
6272 for sFlag in asFlags:
6273 assert sFlag in g_kdEFlagsMnemonics, 'sClass=%s sAttrib=%s sFlag=%s' % (sClass, sAttrib, sFlag,);
6274__sanityCheckEFlagsClasses();
6275
6276## The parsed content of IEMAllInstCommonBodyMacros.h.
6277g_oParsedCommonBodyMacros = None # type: SimpleParser
6278
6279def __parseFileByName(sSrcFile, sDefaultMap, sHostArch):
6280 """
6281 Parses one source file for instruction specfications.
6282 """
6283 #
6284 # Read sSrcFile into a line array.
6285 #
6286 try:
6287 oFile = open(sSrcFile, "r"); # pylint: disable=consider-using-with,unspecified-encoding
6288 except Exception as oXcpt:
6289 raise Exception("failed to open %s for reading: %s" % (sSrcFile, oXcpt,));
6290 try:
6291 asLines = oFile.readlines();
6292 except Exception as oXcpt:
6293 raise Exception("failed to read %s: %s" % (sSrcFile, oXcpt,));
6294 finally:
6295 oFile.close();
6296
6297 #
6298 # On the first call, we parse IEMAllInstCommonBodyMacros.h so we
6299 # can use the macros from it when processing the other files.
6300 #
6301 global g_oParsedCommonBodyMacros;
6302 if g_oParsedCommonBodyMacros is None:
6303 # Locate the file.
6304 sCommonBodyMacros = os.path.join(os.path.split(sSrcFile)[0], 'IEMAllInstCommonBodyMacros.h');
6305 if not os.path.isfile(sCommonBodyMacros):
6306 sCommonBodyMacros = os.path.join(os.path.split(__file__)[0], 'IEMAllInstCommonBodyMacros.h');
6307
6308 # Read it.
6309 try:
6310 with open(sCommonBodyMacros, "r") as oIncFile: # pylint: disable=unspecified-encoding
6311 asIncFiles = oIncFile.readlines();
6312 except Exception as oXcpt:
6313 raise Exception("failed to open/read %s: %s" % (sCommonBodyMacros, oXcpt,));
6314
6315 # Parse it.
6316 try:
6317 oParser = SimpleParser(sCommonBodyMacros, asIncFiles, 'one', sHostArch);
6318 if oParser.parse() != 0:
6319 raise ParserException('%s: errors: See above' % (sCommonBodyMacros, ));
6320 if oParser.cTotalInstr != 0 or oParser.cTotalStubs != 0 or oParser.cTotalTagged != 0 or oParser.cTotalMcBlocks != 0:
6321 raise ParserException('%s: error: Unexpectedly found %u instr, %u tags, %u stubs and %u MCs, expecting zero. %s'
6322 % (sCommonBodyMacros, oParser.cTotalInstr, oParser.cTotalStubs, oParser.cTotalTagged,
6323 oParser.cTotalMcBlocks,
6324 ', '.join(sorted( [str(oMcBlock.iBeginLine) for oMcBlock in g_aoMcBlocks]
6325 + [str(oInstr.iLineCreated) for oInstr in g_aoAllInstructions])),));
6326 except ParserException as oXcpt:
6327 print(str(oXcpt), file = sys.stderr);
6328 raise;
6329 g_oParsedCommonBodyMacros = oParser;
6330
6331 #
6332 # Do the parsing.
6333 #
6334 try:
6335 oParser = SimpleParser(sSrcFile, asLines, sDefaultMap, sHostArch, g_oParsedCommonBodyMacros);
6336 return (oParser.parse(), oParser) ;
6337 except ParserException as oXcpt:
6338 print(str(oXcpt), file = sys.stderr);
6339 raise;
6340
6341
6342def __doTestCopying():
6343 """
6344 Executes the asCopyTests instructions.
6345 """
6346 asErrors = [];
6347 for oDstInstr in g_aoAllInstructions:
6348 if oDstInstr.asCopyTests:
6349 for sSrcInstr in oDstInstr.asCopyTests:
6350 oSrcInstr = g_dAllInstructionsByStat.get(sSrcInstr, None);
6351 if oSrcInstr:
6352 aoSrcInstrs = [oSrcInstr,];
6353 else:
6354 aoSrcInstrs = g_dAllInstructionsByFunction.get(sSrcInstr, []);
6355 if aoSrcInstrs:
6356 for oSrcInstr in aoSrcInstrs:
6357 if oSrcInstr != oDstInstr:
6358 oDstInstr.aoTests.extend(oSrcInstr.aoTests);
6359 else:
6360 asErrors.append('%s:%s: error: @opcopytests reference "%s" matches the destination\n'
6361 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
6362 else:
6363 asErrors.append('%s:%s: error: @opcopytests reference "%s" not found\n'
6364 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
6365
6366 if asErrors:
6367 sys.stderr.write(u''.join(asErrors));
6368 return len(asErrors);
6369
6370
6371def __applyOnlyTest():
6372 """
6373 If g_aoOnlyTestInstructions contains any instructions, drop aoTests from
6374 all other instructions so that only these get tested.
6375 """
6376 if g_aoOnlyTestInstructions:
6377 for oInstr in g_aoAllInstructions:
6378 if oInstr.aoTests:
6379 if oInstr not in g_aoOnlyTestInstructions:
6380 oInstr.aoTests = [];
6381 return 0;
6382
6383## List of all main instruction files, their default maps and file sets (-1 means included it all sets).
6384g_aaoAllInstrFilesAndDefaultMapAndSet = (
6385 ( 'IEMAllInstCommon.cpp.h', 'one', -1, ),
6386 ( 'IEMAllInstOneByte.cpp.h', 'one', 1, ),
6387 ( 'IEMAllInst3DNow.cpp.h', '3dnow', 2, ),
6388 ( 'IEMAllInstTwoByte0f.cpp.h', 'two0f', 2, ),
6389 ( 'IEMAllInstThree0f38.cpp.h', 'three0f38', 3, ),
6390 ( 'IEMAllInstThree0f3a.cpp.h', 'three0f3a', 3, ),
6391 ( 'IEMAllInstVexMap1.cpp.h', 'vexmap1', 4, ),
6392 ( 'IEMAllInstVexMap2.cpp.h', 'vexmap2', 4, ),
6393 ( 'IEMAllInstVexMap3.cpp.h', 'vexmap3', 4, ),
6394);
6395
6396def __parseFilesWorker(asFilesAndDefaultMap, sHostArch):
6397 """
6398 Parses all the IEMAllInstruction*.cpp.h files.
6399
6400 Returns a list of the parsers on success.
6401 Raises exception on failure.
6402 """
6403 sSrcDir = os.path.dirname(os.path.abspath(__file__));
6404 cErrors = 0;
6405 aoParsers = [];
6406 for sFilename, sDefaultMap in asFilesAndDefaultMap:
6407 if not os.path.split(sFilename)[0] and not os.path.exists(sFilename):
6408 sFilename = os.path.join(sSrcDir, sFilename);
6409 cThisErrors, oParser = __parseFileByName(sFilename, sDefaultMap, sHostArch);
6410 cErrors += cThisErrors;
6411 aoParsers.append(oParser);
6412 cErrors += __doTestCopying();
6413 cErrors += __applyOnlyTest();
6414
6415 # Total stub stats:
6416 cTotalStubs = 0;
6417 for oInstr in g_aoAllInstructions:
6418 cTotalStubs += oInstr.fStub;
6419 print('debug: %3s%% / %3s stubs out of %4s instructions and %4s MC blocks in total'
6420 % (cTotalStubs * 100 // len(g_aoAllInstructions), cTotalStubs, len(g_aoAllInstructions), len(g_aoMcBlocks),),
6421 file = sys.stderr);
6422
6423 if cErrors != 0:
6424 raise Exception('%d parse errors' % (cErrors,));
6425 return aoParsers;
6426
6427
6428def parseFiles(asFiles, sHostArch = None):
6429 """
6430 Parses a selection of IEMAllInstruction*.cpp.h files.
6431
6432 Returns a list of the parsers on success.
6433 Raises exception on failure.
6434 """
6435 # Look up default maps for the files and call __parseFilesWorker to do the job.
6436 asFilesAndDefaultMap = [];
6437 for sFilename in asFiles:
6438 sName = os.path.split(sFilename)[1].lower();
6439 sMap = None;
6440 for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet:
6441 if aoInfo[0].lower() == sName:
6442 sMap = aoInfo[1];
6443 break;
6444 if not sMap:
6445 raise Exception('Unable to classify file: %s' % (sFilename,));
6446 asFilesAndDefaultMap.append((sFilename, sMap));
6447
6448 return __parseFilesWorker(asFilesAndDefaultMap, sHostArch);
6449
6450
6451def parseAll(sHostArch = None):
6452 """
6453 Parses all the IEMAllInstruction*.cpp.h files.
6454
6455 Returns a list of the parsers on success.
6456 Raises exception on failure.
6457 """
6458 return __parseFilesWorker([aoInfo[0:2] for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet], sHostArch);
6459
6460
6461#
6462# Generators (may perhaps move later).
6463#
6464def __formatDisassemblerTableEntry(oInstr):
6465 """
6466 """
6467 sMacro = 'OP';
6468 cMaxOperands = 3;
6469 if len(oInstr.aoOperands) > 3:
6470 sMacro = 'OPVEX'
6471 cMaxOperands = 4;
6472 assert len(oInstr.aoOperands) <= cMaxOperands;
6473
6474 #
6475 # Format string.
6476 #
6477 sTmp = '%s("%s' % (sMacro, oInstr.sMnemonic,);
6478 for iOperand, oOperand in enumerate(oInstr.aoOperands):
6479 sTmp += ' ' if iOperand == 0 else ',';
6480 if g_kdOpTypes[oOperand.sType][2][0] != '%': ## @todo remove upper() later.
6481 sTmp += g_kdOpTypes[oOperand.sType][2].upper(); ## @todo remove upper() later.
6482 else:
6483 sTmp += g_kdOpTypes[oOperand.sType][2];
6484 sTmp += '",';
6485 asColumns = [ sTmp, ];
6486
6487 #
6488 # Decoders.
6489 #
6490 iStart = len(asColumns);
6491 if oInstr.sEncoding is None:
6492 pass;
6493 elif oInstr.sEncoding == 'ModR/M':
6494 # ASSUME the first operand is using the ModR/M encoding
6495 assert len(oInstr.aoOperands) >= 1 and oInstr.aoOperands[0].usesModRM(), "oInstr=%s" % (oInstr,);
6496 asColumns.append('IDX_ParseModRM,');
6497 elif oInstr.sEncoding in [ 'prefix', ]:
6498 for oOperand in oInstr.aoOperands:
6499 asColumns.append('0,');
6500 elif oInstr.sEncoding in [ 'fixed', 'VEX.fixed' ]:
6501 pass;
6502 elif oInstr.sEncoding == 'VEX.ModR/M':
6503 asColumns.append('IDX_ParseModRM,');
6504 elif oInstr.sEncoding == 'vex2':
6505 asColumns.append('IDX_ParseVex2b,')
6506 elif oInstr.sEncoding == 'vex3':
6507 asColumns.append('IDX_ParseVex3b,')
6508 elif oInstr.sEncoding in g_dInstructionMaps:
6509 asColumns.append(g_dInstructionMaps[oInstr.sEncoding].sDisParse + ',');
6510 else:
6511 ## @todo
6512 #IDX_ParseTwoByteEsc,
6513 #IDX_ParseGrp1,
6514 #IDX_ParseShiftGrp2,
6515 #IDX_ParseGrp3,
6516 #IDX_ParseGrp4,
6517 #IDX_ParseGrp5,
6518 #IDX_Parse3DNow,
6519 #IDX_ParseGrp6,
6520 #IDX_ParseGrp7,
6521 #IDX_ParseGrp8,
6522 #IDX_ParseGrp9,
6523 #IDX_ParseGrp10,
6524 #IDX_ParseGrp12,
6525 #IDX_ParseGrp13,
6526 #IDX_ParseGrp14,
6527 #IDX_ParseGrp15,
6528 #IDX_ParseGrp16,
6529 #IDX_ParseThreeByteEsc4,
6530 #IDX_ParseThreeByteEsc5,
6531 #IDX_ParseModFence,
6532 #IDX_ParseEscFP,
6533 #IDX_ParseNopPause,
6534 #IDX_ParseInvOpModRM,
6535 assert False, str(oInstr);
6536
6537 # Check for immediates and stuff in the remaining operands.
6538 for oOperand in oInstr.aoOperands[len(asColumns) - iStart:]:
6539 sIdx = g_kdOpTypes[oOperand.sType][0];
6540 #if sIdx != 'IDX_UseModRM':
6541 asColumns.append(sIdx + ',');
6542 asColumns.extend(['0,'] * (cMaxOperands - (len(asColumns) - iStart)));
6543
6544 #
6545 # Opcode and operands.
6546 #
6547 assert oInstr.sDisEnum, str(oInstr);
6548 asColumns.append(oInstr.sDisEnum + ',');
6549 iStart = len(asColumns)
6550 for oOperand in oInstr.aoOperands:
6551 asColumns.append('OP_PARM_' + g_kdOpTypes[oOperand.sType][3] + ',');
6552 asColumns.extend(['OP_PARM_NONE,'] * (cMaxOperands - (len(asColumns) - iStart)));
6553
6554 #
6555 # Flags.
6556 #
6557 sTmp = '';
6558 for sHint in sorted(oInstr.dHints.keys()):
6559 sDefine = g_kdHints[sHint];
6560 if sDefine.startswith('DISOPTYPE_'):
6561 if sTmp:
6562 sTmp += ' | ' + sDefine;
6563 else:
6564 sTmp += sDefine;
6565 if sTmp:
6566 sTmp += '),';
6567 else:
6568 sTmp += '0),';
6569 asColumns.append(sTmp);
6570
6571 #
6572 # Format the columns into a line.
6573 #
6574 aoffColumns = [4, 29, 49, 65, 77, 89, 109, 125, 141, 157, 183, 199];
6575 sLine = '';
6576 for i, s in enumerate(asColumns):
6577 if len(sLine) < aoffColumns[i]:
6578 sLine += ' ' * (aoffColumns[i] - len(sLine));
6579 else:
6580 sLine += ' ';
6581 sLine += s;
6582
6583 # OP("psrlw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE,
6584 # DISOPTYPE_HARMLESS),
6585 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
6586 # { pszOpcode, idxParse1, idxParse2, idxParse3, 0, opcode, param1, param2, param3, 0, 0, optype }
6587 return sLine;
6588
6589def __checkIfShortTable(aoTableOrdered, oMap):
6590 """
6591 Returns (iInstr, cInstructions, fShortTable)
6592 """
6593
6594 # Determin how much we can trim off.
6595 cInstructions = len(aoTableOrdered);
6596 while cInstructions > 0 and aoTableOrdered[cInstructions - 1] is None:
6597 cInstructions -= 1;
6598
6599 iInstr = 0;
6600 while iInstr < cInstructions and aoTableOrdered[iInstr] is None:
6601 iInstr += 1;
6602
6603 # If we can save more than 30%, we go for the short table version.
6604 if iInstr + len(aoTableOrdered) - cInstructions >= len(aoTableOrdered) // 30:
6605 return (iInstr, cInstructions, True);
6606 _ = oMap; # Use this for overriding.
6607
6608 # Output the full table.
6609 return (0, len(aoTableOrdered), False);
6610
6611def generateDisassemblerTables(oDstFile = sys.stdout):
6612 """
6613 Generates disassembler tables.
6614
6615 Returns exit code.
6616 """
6617
6618 #
6619 # Parse all.
6620 #
6621 try:
6622 parseAll();
6623 except Exception as oXcpt:
6624 print('error: parseAll failed: %s' % (oXcpt,), file = sys.stderr);
6625 traceback.print_exc(file = sys.stderr);
6626 return 1;
6627
6628
6629 #
6630 # The disassembler uses a slightly different table layout to save space,
6631 # since several of the prefix varia
6632 #
6633 aoDisasmMaps = [];
6634 for sName, oMap in sorted(iter(g_dInstructionMaps.items()),
6635 key = lambda aKV: aKV[1].sEncoding + ''.join(aKV[1].asLeadOpcodes)):
6636 if oMap.sSelector != 'byte+pfx':
6637 aoDisasmMaps.append(oMap);
6638 else:
6639 # Split the map by prefix.
6640 aoDisasmMaps.append(oMap.copy(oMap.sName, 'none'));
6641 aoDisasmMaps.append(oMap.copy(oMap.sName + '_66', '0x66'));
6642 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F3', '0xf3'));
6643 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F2', '0xf2'));
6644
6645 #
6646 # Dump each map.
6647 #
6648 asHeaderLines = [];
6649 print("debug: maps=%s\n" % (', '.join([oMap.sName for oMap in aoDisasmMaps]),), file = sys.stderr);
6650 for oMap in aoDisasmMaps:
6651 sName = oMap.sName;
6652
6653 if not sName.startswith("vex"): continue; # only looking at the vex maps at the moment.
6654
6655 #
6656 # Get the instructions for the map and see if we can do a short version or not.
6657 #
6658 aoTableOrder = oMap.getInstructionsInTableOrder();
6659 cEntriesPerByte = oMap.getEntriesPerByte();
6660 (iInstrStart, iInstrEnd, fShortTable) = __checkIfShortTable(aoTableOrder, oMap);
6661
6662 #
6663 # Output the table start.
6664 # Note! Short tables are static and only accessible via the map range record.
6665 #
6666 asLines = [];
6667 asLines.append('/* Generated from: %-11s Selector: %-7s Encoding: %-7s Lead bytes opcodes: %s */'
6668 % ( oMap.sName, oMap.sSelector, oMap.sEncoding, ' '.join(oMap.asLeadOpcodes), ));
6669 if fShortTable:
6670 asLines.append('%sconst DISOPCODE %s[] =' % ('static ' if fShortTable else '', oMap.getDisasTableName(),));
6671 else:
6672 asHeaderLines.append('extern const DISOPCODE %s[%d];' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6673 asLines.append( 'const DISOPCODE %s[%d] =' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6674 asLines.append('{');
6675
6676 if fShortTable and (iInstrStart & ((0x10 * cEntriesPerByte) - 1)) != 0:
6677 asLines.append(' /* %#04x: */' % (iInstrStart,));
6678
6679 #
6680 # Output the instructions.
6681 #
6682 iInstr = iInstrStart;
6683 while iInstr < iInstrEnd:
6684 oInstr = aoTableOrder[iInstr];
6685 if (iInstr & ((0x10 * cEntriesPerByte) - 1)) == 0:
6686 if iInstr != iInstrStart:
6687 asLines.append('');
6688 asLines.append(' /* %x */' % ((iInstr // cEntriesPerByte) >> 4,));
6689
6690 if oInstr is None:
6691 # Invalid. Optimize blocks of invalid instructions.
6692 cInvalidInstrs = 1;
6693 while iInstr + cInvalidInstrs < len(aoTableOrder) and aoTableOrder[iInstr + cInvalidInstrs] is None:
6694 cInvalidInstrs += 1;
6695 if (iInstr & (0x10 * cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= 0x10 * cEntriesPerByte:
6696 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (0x10 * cEntriesPerByte,));
6697 iInstr += 0x10 * cEntriesPerByte - 1;
6698 elif cEntriesPerByte > 1:
6699 if (iInstr & (cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= cEntriesPerByte:
6700 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (cEntriesPerByte,));
6701 iInstr += 3;
6702 else:
6703 asLines.append(' /* %#04x/%d */ INVALID_OPCODE,'
6704 % (iInstr // cEntriesPerByte, iInstr % cEntriesPerByte));
6705 else:
6706 asLines.append(' /* %#04x */ INVALID_OPCODE,' % (iInstr));
6707 elif isinstance(oInstr, list):
6708 if len(oInstr) != 0:
6709 asLines.append(' /* %#04x */ ComplicatedListStuffNeedingWrapper, /* \n -- %s */'
6710 % (iInstr, '\n -- '.join([str(oItem) for oItem in oInstr]),));
6711 else:
6712 asLines.append(__formatDisassemblerTableEntry(oInstr));
6713 else:
6714 asLines.append(__formatDisassemblerTableEntry(oInstr));
6715
6716 iInstr += 1;
6717
6718 if iInstrStart >= iInstrEnd:
6719 asLines.append(' /* dummy */ INVALID_OPCODE');
6720
6721 asLines.append('};');
6722 asLines.append('AssertCompile(RT_ELEMENTS(%s) == %s);' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6723
6724 #
6725 # We always emit a map range record, assuming the linker will eliminate the unnecessary ones.
6726 #
6727 asHeaderLines.append('extern const DISOPMAPDESC %sRange;' % (oMap.getDisasRangeName()));
6728 asLines.append('const DISOPMAPDESC %s = { &%s[0], %#04x, RT_ELEMENTS(%s) };'
6729 % (oMap.getDisasRangeName(), oMap.getDisasTableName(), iInstrStart, oMap.getDisasTableName(),));
6730
6731 #
6732 # Write out the lines.
6733 #
6734 oDstFile.write('\n'.join(asLines));
6735 oDstFile.write('\n');
6736 oDstFile.write('\n');
6737 #break; #for now
6738 return 0;
6739
6740if __name__ == '__main__':
6741 sys.exit(generateDisassemblerTables());
6742
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