VirtualBox

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

Last change on this file since 102557 was 102557, checked in by vboxsync, 12 months ago

VMM/IEM: Try deal with running out of executable memory. bugref:10371

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