VirtualBox

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

Last change on this file since 102425 was 102425, checked in by vboxsync, 17 months ago

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

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