VirtualBox

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

Last change on this file since 103184 was 103182, checked in by vboxsync, 16 months ago

VMM/IEM: Implement vpsll[wdq] 'reg/mem' instruction dispatch & emulation
VMM/IEM: Implement vpsll[wdq] 'imm8' instruction decode, dispatch & emulation

Note: some known test failures in IEM (unexpected #AC for 128/256 'mem' instructions)

VMM/IEM: instruction extractor: add VMX_VMI* tokens for VEX_VM inst w/imm byte

ValidationKit/bootsectors: Improve vpsra[wd], vpsrl[wdq] test tables; emulations not implemented yet
ValidationKit/bootsectors: Remove mistaken g_aXcptConfig4psll[] from bs3-cpu-instr-3.c32

bugref:9898

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