VirtualBox

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

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

VMM/IEM: Enabled IEM_MC_FETCH_MEM_U8, IEM_MC_FETCH_MEM_U32 and IEM_MC_FETCH_MEM_U64. bugref:10371

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

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