VirtualBox

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

Last change on this file since 102069 was 102069, checked in by vboxsync, 13 months ago

VMM/IEM: Native translation of IEM_MC_STORE_GREG_U32_CONST. 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: 298.9 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllInstPython.py 102069 2023-11-11 02:40:32Z 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: 102069 $"
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):
1994 ## The source file containing the block.
1995 self.sSrcFile = sSrcFile;
1996 ## The line with the IEM_MC_BEGIN/IEM_MC_DEFER_TO_CIMPL_X_RET statement.
1997 self.iBeginLine = iBeginLine;
1998 ## The offset of the IEM_MC_BEGIN/IEM_MC_DEFER_TO_CIMPL_X_RET statement within the line.
1999 self.offBeginLine = offBeginLine;
2000 ## The line with the IEM_MC_END statement / last line of IEM_MC_DEFER_TO_CIMPL_X_RET.
2001 self.iEndLine = -1;
2002 ## The offset of the IEM_MC_END statement within the line / semicolon offset for defer-to.
2003 self.offEndLine = 0;
2004 ## The offset following the IEM_MC_END/IEM_MC_DEFER_TO_CIMPL_X_RET semicolon.
2005 self.offAfterEnd = 0;
2006 ## The function the block resides in.
2007 self.oFunction = oFunction;
2008 ## The name of the function the block resides in. DEPRECATED.
2009 self.sFunction = oFunction.sName;
2010 ## The block number within the function.
2011 self.iInFunction = iInFunction;
2012 self.cchIndent = cchIndent if cchIndent else offBeginLine;
2013 ##< The raw lines the block is made up of.
2014 self.asLines = [] # type: List[str]
2015 ## Indicates whether the block includes macro expansion parts (kiMacroExp_None,
2016 ## kiMacroExp_Entrie, kiMacroExp_Partial).
2017 self.iMacroExp = self.kiMacroExp_None;
2018 ## IEM_MC_BEGIN: Argument count.
2019 self.cArgs = -1;
2020 ## IEM_MC_ARG, IEM_MC_ARG_CONST, IEM_MC_ARG_LOCAL_REF, IEM_MC_ARG_LOCAL_EFLAGS.
2021 self.aoArgs = [] # type: List[McStmtArg]
2022 ## IEM_MC_BEGIN: Locals count.
2023 self.cLocals = -1;
2024 ## IEM_MC_LOCAL, IEM_MC_LOCAL_CONST, IEM_MC_ARG_LOCAL_EFLAGS.
2025 self.aoLocals = [] # type: List[McStmtVar]
2026 ## IEM_MC_BEGIN: IEM_MC_F_XXX dictionary
2027 self.dsMcFlags = {} # type: Dict[str, bool]
2028 ## IEM_MC_[DEFER_TO|CALL]_CIMPL_XXX: IEM_CIMPL_F_XXX dictionary
2029 self.dsCImplFlags = {} # type: Dict[str, bool]
2030 ## Decoded statements in the block.
2031 self.aoStmts = [] # type: List[McStmt]
2032
2033 def complete(self, iEndLine, offEndLine, offAfterEnd, asLines):
2034 """
2035 Completes the microcode block.
2036 """
2037 assert self.iEndLine == -1;
2038 self.iEndLine = iEndLine;
2039 self.offEndLine = offEndLine;
2040 self.offAfterEnd = offAfterEnd;
2041 self.asLines = asLines;
2042
2043 def raiseDecodeError(self, sRawCode, off, sMessage):
2044 """ Raises a decoding error. """
2045 offStartOfLine = sRawCode.rfind('\n', 0, off) + 1;
2046 iLine = sRawCode.count('\n', 0, off);
2047 raise ParserException('%s:%d:%d: parsing error: %s'
2048 % (self.sSrcFile, self.iBeginLine + iLine, off - offStartOfLine + 1, sMessage,));
2049
2050 def raiseStmtError(self, sName, sMessage):
2051 """ Raises a statement parser error. """
2052 raise ParserException('%s:%d: %s: parsing error: %s' % (self.sSrcFile, self.iBeginLine, sName, sMessage,));
2053
2054 def checkStmtParamCount(self, sName, asParams, cParamsExpected):
2055 """ Check the parameter count, raising an error it doesn't match. """
2056 if len(asParams) != cParamsExpected:
2057 raise ParserException('%s:%d: %s: Expected %s parameters, found %s!'
2058 % (self.sSrcFile, self.iBeginLine, sName, cParamsExpected, len(asParams),));
2059 return True;
2060
2061 @staticmethod
2062 def parseMcGeneric(oSelf, sName, asParams):
2063 """ Generic parser that returns a plain McStmt object. """
2064 _ = oSelf;
2065 return McStmt(sName, asParams);
2066
2067 @staticmethod
2068 def parseMcGenericCond(oSelf, sName, asParams):
2069 """ Generic parser that returns a plain McStmtCond object. """
2070 _ = oSelf;
2071 return McStmtCond(sName, asParams);
2072
2073 @staticmethod
2074 def parseMcBegin(oSelf, sName, asParams):
2075 """ IEM_MC_BEGIN """
2076 oSelf.checkStmtParamCount(sName, asParams, 4);
2077 if oSelf.cArgs != -1 or oSelf.cLocals != -1 or oSelf.dsMcFlags:
2078 oSelf.raiseStmtError(sName, 'Used more than once!');
2079 oSelf.cArgs = int(asParams[0]);
2080 oSelf.cLocals = int(asParams[1]);
2081
2082 if asParams[2] != '0':
2083 for sFlag in asParams[2].split('|'):
2084 sFlag = sFlag.strip();
2085 if sFlag not in g_kdMcFlags:
2086 oSelf.raiseStmtError(sName, 'Unknown flag: %s' % (sFlag, ));
2087 oSelf.dsMcFlags[sFlag] = True;
2088 for sFlag2 in g_kdMcFlags[sFlag]:
2089 oSelf.dsMcFlags[sFlag2] = True;
2090
2091 if asParams[3] != '0':
2092 oSelf.parseCImplFlags(sName, asParams[3]);
2093
2094 return McBlock.parseMcGeneric(oSelf, sName, asParams);
2095
2096 @staticmethod
2097 def parseMcArg(oSelf, sName, asParams):
2098 """ IEM_MC_ARG """
2099 oSelf.checkStmtParamCount(sName, asParams, 3);
2100 oStmt = McStmtArg(sName, asParams, asParams[0], asParams[1], int(asParams[2]));
2101 oSelf.aoArgs.append(oStmt);
2102 return oStmt;
2103
2104 @staticmethod
2105 def parseMcArgConst(oSelf, sName, asParams):
2106 """ IEM_MC_ARG_CONST """
2107 oSelf.checkStmtParamCount(sName, asParams, 4);
2108 oStmt = McStmtArg(sName, asParams, asParams[0], asParams[1], int(asParams[3]), sConstValue = asParams[2]);
2109 oSelf.aoArgs.append(oStmt);
2110 return oStmt;
2111
2112 @staticmethod
2113 def parseMcArgLocalRef(oSelf, sName, asParams):
2114 """ IEM_MC_ARG_LOCAL_REF """
2115 oSelf.checkStmtParamCount(sName, asParams, 4);
2116 oStmt = McStmtArg(sName, asParams, asParams[0], asParams[1], int(asParams[3]), sRef = asParams[2], sRefType = 'local');
2117 oSelf.aoArgs.append(oStmt);
2118 return oStmt;
2119
2120 @staticmethod
2121 def parseMcArgLocalEFlags(oSelf, sName, asParams):
2122 """ IEM_MC_ARG_LOCAL_EFLAGS """
2123 oSelf.checkStmtParamCount(sName, asParams, 3);
2124 # Note! We split this one up into IEM_MC_LOCAL_VAR and IEM_MC_ARG_LOCAL_REF.
2125 oStmtLocal = McStmtVar('IEM_MC_LOCAL', ['uint32_t', asParams[1],], 'uint32_t', asParams[1]);
2126 oSelf.aoLocals.append(oStmtLocal);
2127 oStmtArg = McStmtArg('IEM_MC_ARG_LOCAL_REF', ['uint32_t *', asParams[0], asParams[1], asParams[2]],
2128 'uint32_t *', asParams[0], int(asParams[2]), sRef = asParams[1], sRefType = 'local');
2129 oSelf.aoArgs.append(oStmtArg);
2130 return (oStmtLocal, oStmtArg,);
2131
2132 @staticmethod
2133 def parseMcImplicitAvxAArgs(oSelf, sName, asParams):
2134 """ IEM_MC_IMPLICIT_AVX_AIMPL_ARGS """
2135 oSelf.checkStmtParamCount(sName, asParams, 0);
2136 # Note! Translate to IEM_MC_ARG_CONST
2137 oStmt = McStmtArg('IEM_MC_ARG_CONST', ['PX86XSAVEAREA', 'pXState', '&pVCpu->cpum.GstCtx.XState', '0'],
2138 'PX86XSAVEAREA', 'pXState', 0, '&pVCpu->cpum.GstCtx.XState');
2139 oSelf.aoArgs.append(oStmt);
2140 return oStmt;
2141
2142 @staticmethod
2143 def parseMcLocal(oSelf, sName, asParams):
2144 """ IEM_MC_LOCAL """
2145 oSelf.checkStmtParamCount(sName, asParams, 2);
2146 oStmt = McStmtVar(sName, asParams, asParams[0], asParams[1]);
2147 oSelf.aoLocals.append(oStmt);
2148 return oStmt;
2149
2150 @staticmethod
2151 def parseMcLocalAssign(oSelf, sName, asParams):
2152 """ IEM_MC_LOCAL_ASSIGN """
2153 oSelf.checkStmtParamCount(sName, asParams, 3);
2154 oStmt = McStmtVar(sName, asParams, asParams[0], asParams[1], sValue = asParams[2]);
2155 oSelf.aoLocals.append(oStmt);
2156 return oStmt;
2157
2158 @staticmethod
2159 def parseMcLocalConst(oSelf, sName, asParams):
2160 """ IEM_MC_LOCAL_CONST """
2161 oSelf.checkStmtParamCount(sName, asParams, 3);
2162 oStmt = McStmtVar(sName, asParams, asParams[0], asParams[1], sValue = asParams[2]);
2163 oSelf.aoLocals.append(oStmt);
2164 return oStmt;
2165
2166 @staticmethod
2167 def parseMcCallAImpl(oSelf, sName, asParams):
2168 """ IEM_MC_CALL_AIMPL_3|4 """
2169 cArgs = int(sName[-1]);
2170 oSelf.checkStmtParamCount(sName, asParams, 2 + cArgs);
2171 return McStmtCall(sName, asParams, 1, 0);
2172
2173 @staticmethod
2174 def parseMcCallVoidAImpl(oSelf, sName, asParams):
2175 """ IEM_MC_CALL_VOID_AIMPL_2|3 """
2176 cArgs = int(sName[-1]);
2177 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2178 return McStmtCall(sName, asParams, 0);
2179
2180 @staticmethod
2181 def parseMcCallAvxAImpl(oSelf, sName, asParams):
2182 """ IEM_MC_CALL_AVX_AIMPL_2|3 """
2183 cArgs = int(sName[-1]);
2184 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2185 return McStmtCall(sName, asParams, 0);
2186
2187 @staticmethod
2188 def parseMcCallFpuAImpl(oSelf, sName, asParams):
2189 """ IEM_MC_CALL_FPU_AIMPL_1|2|3 """
2190 cArgs = int(sName[-1]);
2191 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2192 return McStmtCall(sName, asParams, 0);
2193
2194 @staticmethod
2195 def parseMcCallMmxAImpl(oSelf, sName, asParams):
2196 """ IEM_MC_CALL_MMX_AIMPL_2|3 """
2197 cArgs = int(sName[-1]);
2198 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2199 return McStmtCall(sName, asParams, 0);
2200
2201 @staticmethod
2202 def parseMcCallSseAImpl(oSelf, sName, asParams):
2203 """ IEM_MC_CALL_SSE_AIMPL_2|3 """
2204 cArgs = int(sName[-1]);
2205 oSelf.checkStmtParamCount(sName, asParams, 1 + cArgs);
2206 return McStmtCall(sName, asParams, 0);
2207
2208 def parseCImplFlags(self, sName, sFlags):
2209 """
2210 Helper for parseMcCallCImpl and parseMcDeferToCImpl to validate and
2211 merge a bunch of IEM_CIMPL_F_XXX value into dsCImplFlags.
2212 """
2213 if sFlags != '0':
2214 sFlags = self.stripComments(sFlags);
2215 #print('debug: %s: %s' % (self.oFunction.sName,' | '.join(''.join(sFlags.split()).split('|')),));
2216 for sFlag in sFlags.split('|'):
2217 sFlag = sFlag.strip();
2218 if sFlag[0] == '(': sFlag = sFlag[1:].strip();
2219 if sFlag[-1] == ')': sFlag = sFlag[:-1].strip();
2220 #print('debug: %s' % sFlag)
2221 if sFlag not in g_kdCImplFlags:
2222 if sFlag == '0':
2223 continue;
2224 self.raiseStmtError(sName, 'Unknown flag: %s' % (sFlag, ));
2225 self.dsCImplFlags[sFlag] = True;
2226 for sFlag2 in g_kdCImplFlags[sFlag]:
2227 self.dsCImplFlags[sFlag2] = True;
2228 return None;
2229
2230 @staticmethod
2231 def parseMcCallCImpl(oSelf, sName, asParams):
2232 """ IEM_MC_CALL_CIMPL_0|1|2|3|4|5 """
2233 cArgs = int(sName[-1]);
2234 oSelf.checkStmtParamCount(sName, asParams, 3 + cArgs);
2235 oSelf.parseCImplFlags(sName, asParams[0]);
2236 return McStmtCall(sName, asParams, 2);
2237
2238 @staticmethod
2239 def parseMcDeferToCImpl(oSelf, sName, asParams):
2240 """ IEM_MC_DEFER_TO_CIMPL_[0|1|2|3]_RET """
2241 # Note! This code is called by workerIemMcDeferToCImplXRet.
2242 #print('debug: %s, %s,...' % (sName, asParams[0],));
2243 cArgs = int(sName[-5]);
2244 oSelf.checkStmtParamCount(sName, asParams, 3 + cArgs);
2245 oSelf.parseCImplFlags(sName, asParams[0]);
2246 return McStmtCall(sName, asParams, 2);
2247
2248 @staticmethod
2249 def stripComments(sCode):
2250 """ Returns sCode with comments removed. """
2251 off = 0;
2252 while off < len(sCode):
2253 off = sCode.find('/', off);
2254 if off < 0 or off + 1 >= len(sCode):
2255 break;
2256
2257 if sCode[off + 1] == '/':
2258 # C++ comment.
2259 offEnd = sCode.find('\n', off + 2);
2260 if offEnd < 0:
2261 return sCode[:off].rstrip();
2262 sCode = sCode[ : off] + sCode[offEnd : ];
2263 off += 1;
2264
2265 elif sCode[off + 1] == '*':
2266 # C comment
2267 offEnd = sCode.find('*/', off + 2);
2268 if offEnd < 0:
2269 return sCode[:off].rstrip();
2270 sSep = ' ';
2271 if (off > 0 and sCode[off - 1].isspace()) or (offEnd + 2 < len(sCode) and sCode[offEnd + 2].isspace()):
2272 sSep = '';
2273 sCode = sCode[ : off] + sSep + sCode[offEnd + 2 : ];
2274 off += len(sSep);
2275
2276 else:
2277 # Not a comment.
2278 off += 1;
2279 return sCode;
2280
2281 @staticmethod
2282 def extractParam(sCode, offParam):
2283 """
2284 Extracts the parameter value at offParam in sCode.
2285 Returns stripped value and the end offset of the terminating ',' or ')'.
2286 """
2287 # Extract it.
2288 cNesting = 0;
2289 offStart = offParam;
2290 while offParam < len(sCode):
2291 ch = sCode[offParam];
2292 if ch == '(':
2293 cNesting += 1;
2294 elif ch == ')':
2295 if cNesting == 0:
2296 break;
2297 cNesting -= 1;
2298 elif ch == ',' and cNesting == 0:
2299 break;
2300 offParam += 1;
2301 return (sCode[offStart : offParam].strip(), offParam);
2302
2303 @staticmethod
2304 def extractParams(sCode, offOpenParen):
2305 """
2306 Parses a parameter list.
2307 Returns the list of parameter values and the offset of the closing parentheses.
2308 Returns (None, len(sCode)) on if no closing parentheses was found.
2309 """
2310 assert sCode[offOpenParen] == '(';
2311 asParams = [];
2312 off = offOpenParen + 1;
2313 while off < len(sCode):
2314 ch = sCode[off];
2315 if ch.isspace():
2316 off += 1;
2317 elif ch != ')':
2318 (sParam, off) = McBlock.extractParam(sCode, off);
2319 asParams.append(sParam);
2320 assert off < len(sCode), 'off=%s sCode=%s:"%s"' % (off, len(sCode), sCode,);
2321 if sCode[off] == ',':
2322 off += 1;
2323 else:
2324 return (asParams, off);
2325 return (None, off);
2326
2327 @staticmethod
2328 def findClosingBraces(sCode, off, offStop):
2329 """
2330 Finds the matching '}' for the '{' at off in sCode.
2331 Returns offset of the matching '}' on success, otherwise -1.
2332
2333 Note! Does not take comments into account.
2334 """
2335 cDepth = 1;
2336 off += 1;
2337 while off < offStop:
2338 offClose = sCode.find('}', off, offStop);
2339 if offClose < 0:
2340 break;
2341 cDepth += sCode.count('{', off, offClose);
2342 cDepth -= 1;
2343 if cDepth == 0:
2344 return offClose;
2345 off = offClose + 1;
2346 return -1;
2347
2348 @staticmethod
2349 def countSpacesAt(sCode, off, offStop):
2350 """ Returns the number of space characters at off in sCode. """
2351 offStart = off;
2352 while off < offStop and sCode[off].isspace():
2353 off += 1;
2354 return off - offStart;
2355
2356 @staticmethod
2357 def skipSpacesAt(sCode, off, offStop):
2358 """ Returns first offset at or after off for a non-space character. """
2359 return off + McBlock.countSpacesAt(sCode, off, offStop);
2360
2361 @staticmethod
2362 def isSubstrAt(sStr, off, sSubStr):
2363 """ Returns true of sSubStr is found at off in sStr. """
2364 return sStr[off : off + len(sSubStr)] == sSubStr;
2365
2366 koReCppCtrlStmts = re.compile(r'\b(if\s*[(]|else\b|while\s*[(]|for\s*[(]|do\b)');
2367 koReIemDecoderVars = re.compile( r'iem\.s\.(fPrefixes|uRexReg|uRexB|uRexIndex|iEffSeg|offModRm|cbOpcode|offOpcode'
2368 + r'|enmEffOpSize|enmDefOpSize|enmDefAddrMode|enmEffAddrMode|idxPrefix'
2369 + r'|uVex3rdReg|uVexLength|fEvxStuff|uFpuOpcode|abOpcode'
2370 + r')');
2371
2372 def decodeCode(self, sRawCode, off = 0, offStop = -1, iLevel = 0): # pylint: disable=too-many-statements,too-many-branches
2373 """
2374 Decodes sRawCode[off : offStop].
2375
2376 Returns list of McStmt instances.
2377 Raises ParserException on failure.
2378 """
2379 if offStop < 0:
2380 offStop = len(sRawCode);
2381 aoStmts = [];
2382 while off < offStop:
2383 ch = sRawCode[off];
2384
2385 #
2386 # Skip spaces and comments.
2387 #
2388 if ch.isspace():
2389 off += 1;
2390
2391 elif ch == '/':
2392 ch = sRawCode[off + 1];
2393 if ch == '/': # C++ comment.
2394 off = sRawCode.find('\n', off + 2);
2395 if off < 0:
2396 break;
2397 off += 1;
2398 elif ch == '*': # C comment.
2399 off = sRawCode.find('*/', off + 2);
2400 if off < 0:
2401 break;
2402 off += 2;
2403 else:
2404 self.raiseDecodeError(sRawCode, off, 'Unexpected "/"');
2405
2406 #
2407 # Is it a MC statement.
2408 #
2409 elif ch == 'I' and sRawCode[off : off + len('IEM_MC_')] == 'IEM_MC_':
2410 # All MC statements ends with a semicolon, except for conditionals which ends with a '{'.
2411 # Extract it and strip comments from it.
2412 if not self.isSubstrAt(sRawCode, off, 'IEM_MC_IF_'):
2413 offEnd = sRawCode.find(';', off + len('IEM_MC_'));
2414 if offEnd <= off:
2415 self.raiseDecodeError(sRawCode, off, 'MC statement without a ";"');
2416 else:
2417 offEnd = sRawCode.find('{', off + len('IEM_MC_IF_'));
2418 if offEnd <= off:
2419 self.raiseDecodeError(sRawCode, off, 'MC conditional statement without a "{"');
2420 if sRawCode.find(';', off + len('IEM_MC_IF_'), offEnd) > off:
2421 self.raiseDecodeError(sRawCode, off, 'MC conditional statement without an immediate "{"');
2422 offEnd -= 1;
2423 while offEnd > off and sRawCode[offEnd - 1].isspace():
2424 offEnd -= 1;
2425
2426 sRawStmt = self.stripComments(sRawCode[off : offEnd]);
2427
2428 # Isolate the statement name.
2429 offOpenParen = sRawStmt.find('(');
2430 if offOpenParen < 0:
2431 self.raiseDecodeError(sRawCode, off, 'MC statement without a "("');
2432 sName = sRawStmt[: offOpenParen].strip();
2433
2434 # Extract the parameters.
2435 (asParams, offCloseParen) = self.extractParams(sRawStmt, offOpenParen);
2436 if asParams is None:
2437 self.raiseDecodeError(sRawCode, off, 'MC statement without a closing parenthesis');
2438 if offCloseParen + 1 != len(sRawStmt):
2439 self.raiseDecodeError(sRawCode, off,
2440 'Unexpected code following MC statement: %s' % (sRawStmt[offCloseParen + 1:]));
2441
2442 # Hand it to the handler.
2443 fnParser = g_dMcStmtParsers.get(sName);
2444 if not fnParser:
2445 self.raiseDecodeError(sRawCode, off, 'Unknown MC statement: %s' % (sName,));
2446 fnParser = fnParser[0];
2447 oStmt = fnParser(self, sName, asParams);
2448 if not isinstance(oStmt, (list, tuple)):
2449 aoStmts.append(oStmt);
2450 else:
2451 aoStmts.extend(oStmt);
2452
2453 #
2454 # If conditional, we need to parse the whole statement.
2455 #
2456 # For reasons of simplicity, we assume the following structure
2457 # and parse each branch in a recursive call:
2458 # IEM_MC_IF_XXX() {
2459 # IEM_MC_WHATEVER();
2460 # } IEM_MC_ELSE() {
2461 # IEM_MC_WHATEVER();
2462 # } IEM_MC_ENDIF();
2463 #
2464 if sName.startswith('IEM_MC_IF_'):
2465 if iLevel > 1:
2466 self.raiseDecodeError(sRawCode, off, 'Too deep nesting of conditionals.');
2467
2468 # Find start of the IF block:
2469 offBlock1 = self.skipSpacesAt(sRawCode, offEnd, offStop);
2470 if sRawCode[offBlock1] != '{':
2471 self.raiseDecodeError(sRawCode, offBlock1, 'Expected "{" following %s' % (sName,));
2472
2473 # Find the end of it.
2474 offBlock1End = self.findClosingBraces(sRawCode, offBlock1, offStop);
2475 if offBlock1End < 0:
2476 self.raiseDecodeError(sRawCode, offBlock1, 'No matching "}" closing IF block of %s' % (sName,));
2477
2478 oStmt.aoIfBranch = self.decodeCode(sRawCode, offBlock1 + 1, offBlock1End, iLevel + 1);
2479
2480 # Is there an else section?
2481 off = self.skipSpacesAt(sRawCode, offBlock1End + 1, offStop);
2482 if self.isSubstrAt(sRawCode, off, 'IEM_MC_ELSE'):
2483 off = self.skipSpacesAt(sRawCode, off + len('IEM_MC_ELSE'), offStop);
2484 if sRawCode[off] != '(':
2485 self.raiseDecodeError(sRawCode, off, 'Expected "(" following IEM_MC_ELSE"');
2486 off = self.skipSpacesAt(sRawCode, off + 1, offStop);
2487 if sRawCode[off] != ')':
2488 self.raiseDecodeError(sRawCode, off, 'Expected ")" following IEM_MC_ELSE("');
2489
2490 # Find start of the ELSE block.
2491 offBlock2 = self.skipSpacesAt(sRawCode, off + 1, offStop);
2492 if sRawCode[offBlock2] != '{':
2493 self.raiseDecodeError(sRawCode, offBlock2, 'Expected "{" following IEM_MC_ELSE()"');
2494
2495 # Find the end of it.
2496 offBlock2End = self.findClosingBraces(sRawCode, offBlock2, offStop);
2497 if offBlock2End < 0:
2498 self.raiseDecodeError(sRawCode, offBlock2, 'No matching "}" closing ELSE block of %s' % (sName,));
2499
2500 oStmt.aoElseBranch = self.decodeCode(sRawCode, offBlock2 + 1, offBlock2End, iLevel + 1);
2501 off = self.skipSpacesAt(sRawCode, offBlock2End + 1, offStop);
2502
2503 # Parse past the endif statement.
2504 if not self.isSubstrAt(sRawCode, off, 'IEM_MC_ENDIF'):
2505 self.raiseDecodeError(sRawCode, off, 'Expected IEM_MC_ENDIF for closing %s' % (sName,));
2506 off = self.skipSpacesAt(sRawCode, off + len('IEM_MC_ENDIF'), offStop);
2507 if sRawCode[off] != '(':
2508 self.raiseDecodeError(sRawCode, off, 'Expected "(" following IEM_MC_ENDIF"');
2509 off = self.skipSpacesAt(sRawCode, off + 1, offStop);
2510 if sRawCode[off] != ')':
2511 self.raiseDecodeError(sRawCode, off, 'Expected ")" following IEM_MC_ENDIF("');
2512 off = self.skipSpacesAt(sRawCode, off + 1, offStop);
2513 if sRawCode[off] != ';':
2514 self.raiseDecodeError(sRawCode, off, 'Expected ";" following IEM_MC_ENDIF()"');
2515 off += 1;
2516
2517 else:
2518 # Advance.
2519 off = offEnd + 1;
2520
2521 #
2522 # Otherwise it must be a C/C++ statement of sorts.
2523 #
2524 else:
2525 # Find the end of the statement. if and else requires special handling.
2526 sCondExpr = None;
2527 oMatch = self.koReCppCtrlStmts.match(sRawCode, off);
2528 if oMatch:
2529 if oMatch.group(1)[-1] == '(':
2530 (sCondExpr, offEnd) = self.extractParam(sRawCode, oMatch.end());
2531 else:
2532 offEnd = oMatch.end();
2533 if not oMatch.group(1).startswith('if') and oMatch.group(1) != 'else':
2534 self.raiseDecodeError(sRawCode, off, 'Only if/else control statements allowed: %s' % (oMatch.group(1),));
2535 elif ch == '#':
2536 offEnd = sRawCode.find('\n', off, offStop);
2537 if offEnd < 0:
2538 offEnd = offStop;
2539 offEnd -= 1;
2540 while offEnd > off and sRawCode[offEnd - 1].isspace():
2541 offEnd -= 1;
2542 else:
2543 offEnd = sRawCode.find(';', off);
2544 if offEnd < 0:
2545 self.raiseDecodeError(sRawCode, off, 'C++ statement without a ";"');
2546
2547 # Check this and the following statement whether it might have
2548 # something to do with decoding. This is a statement filter
2549 # criteria when generating the threaded functions blocks.
2550 offNextEnd = sRawCode.find(';', offEnd + 1);
2551 fDecode = ( sRawCode.find('IEM_OPCODE_', off, max(offEnd, offNextEnd)) >= 0
2552 or sRawCode.find('IEMOP_HLP_DONE_', off, max(offEnd, offNextEnd)) >= 0
2553 or sRawCode.find('IEMOP_HLP_DECODED_', off, offEnd) >= 0
2554 or sRawCode.find('IEMOP_HLP_RAISE_UD_IF_MISSING_GUEST_FEATURE', off, offEnd) >= 0
2555 or sRawCode.find('IEMOP_HLP_VMX_INSTR', off, offEnd) >= 0
2556 or sRawCode.find('IEMOP_HLP_IN_VMX_OPERATION', off, offEnd) >= 0 ## @todo wrong
2557 );
2558
2559 if not oMatch:
2560 if ch != '#':
2561 aoStmts.append(McCppGeneric(sRawCode[off : offEnd + 1], fDecode));
2562 else:
2563 aoStmts.append(McCppPreProc(sRawCode[off : offEnd + 1]));
2564 off = offEnd + 1;
2565 elif oMatch.group(1).startswith('if'):
2566 #
2567 # if () xxx [else yyy] statement.
2568 #
2569 oStmt = McCppCond(sCondExpr, fDecode);
2570 aoStmts.append(oStmt);
2571 off = offEnd + 1;
2572
2573 # Following the if () we can either have a {} containing zero or more statements
2574 # or we have a single statement.
2575 offBlock1 = self.skipSpacesAt(sRawCode, offEnd + 1, offStop);
2576 if sRawCode[offBlock1] == '{':
2577 offBlock1End = self.findClosingBraces(sRawCode, offBlock1, offStop);
2578 if offBlock1End < 0:
2579 self.raiseDecodeError(sRawCode, offBlock1, 'No matching "}" closing if block');
2580 offBlock1 += 1;
2581 else:
2582 offBlock1End = sRawCode.find(';', offBlock1, offStop);
2583 if offBlock1End < 0:
2584 self.raiseDecodeError(sRawCode, off, 'Expected ";" terminating one-line if block"');
2585
2586 oStmt.aoIfBranch = self.decodeCode(sRawCode, offBlock1, offBlock1End, iLevel + 1);
2587
2588 # The else is optional and can likewise be followed by {} or a single statement.
2589 off = self.skipSpacesAt(sRawCode, offBlock1End + 1, offStop);
2590 if self.isSubstrAt(sRawCode, off, 'else') and sRawCode[off + len('else')].isspace():
2591 offBlock2 = self.skipSpacesAt(sRawCode, off + len('else'), offStop);
2592 if sRawCode[offBlock2] == '{':
2593 offBlock2End = self.findClosingBraces(sRawCode, offBlock2, offStop);
2594 if offBlock2End < 0:
2595 self.raiseDecodeError(sRawCode, offBlock2, 'No matching "}" closing else block');
2596 offBlock2 += 1;
2597 else:
2598 offBlock2End = sRawCode.find(';', offBlock2, offStop);
2599 if offBlock2End < 0:
2600 self.raiseDecodeError(sRawCode, off, 'Expected ";" terminating one-line else block"');
2601
2602 oStmt.aoElseBranch = self.decodeCode(sRawCode, offBlock2, offBlock2End, iLevel + 1);
2603 off = offBlock2End + 1;
2604
2605 elif oMatch.group(1) == 'else':
2606 # Problematic 'else' branch, typically involving #ifdefs.
2607 self.raiseDecodeError(sRawCode, off, 'Mixed up else/#ifdef or something confusing us.');
2608
2609 return aoStmts;
2610
2611 def decode(self):
2612 """
2613 Decodes the block, populating self.aoStmts if necessary.
2614 Returns the statement list.
2615 Raises ParserException on failure.
2616 """
2617 if not self.aoStmts:
2618 self.aoStmts = self.decodeCode(''.join(self.asLines));
2619 return self.aoStmts;
2620
2621
2622 def checkForTooEarlyEffSegUse(self, aoStmts):
2623 """
2624 Checks if iEffSeg is used before the effective address has been decoded.
2625 Returns None on success, error string on failure.
2626
2627 See r158454 for an example of this issue.
2628 """
2629
2630 # Locate the IEM_MC_CALC_RM_EFF_ADDR statement, if found, scan backwards
2631 # for IEMCPU::iEffSeg references. No need to check conditional branches,
2632 # as we're ASSUMING these will not occur before address calculation.
2633 for iStmt, oStmt in enumerate(aoStmts):
2634 if oStmt.sName == 'IEM_MC_CALC_RM_EFF_ADDR':
2635 while iStmt > 0:
2636 iStmt -= 1;
2637 oStmt = aoStmts[iStmt];
2638 for sArg in oStmt.asParams:
2639 if sArg.find('pVCpu->iem.s.iEffSeg') >= 0:
2640 return "statement #%u: pVCpu->iem.s.iEffSeg is used prior to IEM_MC_CALC_RM_EFF_ADDR!" % (iStmt + 1,);
2641 break;
2642 return None;
2643
2644 koReCppFirstWord = re.compile(r'^\s*(\w+)[ (;]');
2645 kdDecodeCppStmtOkayAfterDone = {
2646 'IEMOP_HLP_IN_VMX_OPERATION': True,
2647 'IEMOP_HLP_VMX_INSTR': True,
2648 };
2649
2650 def checkForDoneDecoding(self, aoStmts):
2651 """
2652 Checks that the block contains a IEMOP_HLP_DONE_*DECODING* macro
2653 invocation.
2654 Returns None on success, error string on failure.
2655
2656 This ensures safe instruction restarting in case the recompiler runs
2657 out of TB resources during recompilation (e.g. aRanges or aGCPhysPages
2658 entries).
2659 """
2660
2661 # The IEMOP_HLP_DONE_ stuff is not allowed inside conditionals, so we
2662 # don't need to look.
2663 cIemOpHlpDone = 0;
2664 for iStmt, oStmt in enumerate(aoStmts):
2665 if oStmt.isCppStmt():
2666 #print('dbg: #%u[%u]: %s %s (%s)'
2667 # % (iStmt + 1, cIemOpHlpDone, oStmt.sName, 'd' if oStmt.fDecode else 'r', oStmt.asParams[0],));
2668
2669 oMatch = self.koReCppFirstWord.match(oStmt.asParams[0]);
2670 if oMatch:
2671 sFirstWord = oMatch.group(1);
2672 if ( sFirstWord.startswith('IEMOP_HLP_DONE_')
2673 or sFirstWord.startswith('IEMOP_HLP_DECODED_')):
2674 cIemOpHlpDone += 1;
2675 elif cIemOpHlpDone > 0 and oStmt.fDecode and sFirstWord not in self.kdDecodeCppStmtOkayAfterDone:
2676 return "statement #%u: Decoding statement following IEMOP_HLP_DONE_*DECODING*!" % (iStmt + 1,);
2677 #else: print('dbg: #%u[%u]: %s' % (iStmt + 1, cIemOpHlpDone, oStmt.asParams[0]));
2678 else:
2679 #print('dbg: #%u[%u]: %s' % (iStmt + 1, cIemOpHlpDone, oStmt.sName));
2680 if oStmt.sName.startswith('IEM_MC_DEFER_TO_CIMPL_') and iStmt == 0: # implicit
2681 cIemOpHlpDone += 1;
2682 elif cIemOpHlpDone == 0 and g_dMcStmtParsers.get(oStmt.sName, (None, False))[1]:
2683 return "statement #%u: State modifying MC statement before IEMOP_HLP_DONE_*DECODING*!" % (iStmt + 1,);
2684 elif cIemOpHlpDone > 0 and oStmt.sName in ('IEM_MC_CALC_RM_EFF_ADDR',):
2685 return "statement #%u: Decoding statement following IEMOP_HLP_DONE_*DECODING*!" % (iStmt + 1,);
2686 if cIemOpHlpDone == 1:
2687 return None;
2688 if cIemOpHlpDone > 1:
2689 return "Block has more than one IEMOP_HLP_DONE_*DECODING* invocation!";
2690 return "Block is missing IEMOP_HLP_DONE_*DECODING* invocation!";
2691
2692 def check(self):
2693 """
2694 Performs some sanity checks on the block.
2695 Returns error string list, empty if all is fine.
2696 """
2697 aoStmts = self.decode();
2698 asRet = [];
2699
2700 sRet = self.checkForTooEarlyEffSegUse(aoStmts);
2701 if sRet:
2702 asRet.append(sRet);
2703
2704 sRet = self.checkForDoneDecoding(aoStmts);
2705 if sRet:
2706 asRet.append(sRet);
2707
2708 return asRet;
2709
2710
2711
2712## IEM_MC_XXX -> parser + info dictionary.
2713#
2714# The info columns:
2715# - col 0: boolean entry indicating whether the statement modifies state and
2716# must not be used before IEMOP_HL_DONE_*.
2717# - col 1: boolean entry indicating native recompiler support.
2718#
2719# The raw table was generated via the following command
2720# sed -n -e "s/^# *define *\(IEM_MC_[A-Z_0-9]*\)[ (].*$/ '\1': McBlock.parseMcGeneric,/p" include/IEMMc.h \
2721# | sort | uniq | gawk "{printf """ %%-60s (%%s, True)\n""", $1, $2}"
2722g_dMcStmtParsers = {
2723 'IEM_MC_ACTUALIZE_AVX_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, ),
2724 'IEM_MC_ACTUALIZE_AVX_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, ),
2725 'IEM_MC_ACTUALIZE_FPU_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, ),
2726 'IEM_MC_ACTUALIZE_FPU_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, ),
2727 'IEM_MC_ACTUALIZE_SSE_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, ),
2728 'IEM_MC_ACTUALIZE_SSE_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, ),
2729 'IEM_MC_ADD_GREG_U16': (McBlock.parseMcGeneric, True, False, ),
2730 'IEM_MC_ADD_GREG_U16_TO_LOCAL': (McBlock.parseMcGeneric, False, False, ),
2731 'IEM_MC_ADD_GREG_U32': (McBlock.parseMcGeneric, True, False, ),
2732 'IEM_MC_ADD_GREG_U32_TO_LOCAL': (McBlock.parseMcGeneric, False, False, ),
2733 'IEM_MC_ADD_GREG_U64': (McBlock.parseMcGeneric, True, False, ),
2734 'IEM_MC_ADD_GREG_U64_TO_LOCAL': (McBlock.parseMcGeneric, False, False, ),
2735 'IEM_MC_ADD_GREG_U8_TO_LOCAL': (McBlock.parseMcGeneric, False, False, ),
2736 'IEM_MC_ADD_LOCAL_S16_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, False, ),
2737 'IEM_MC_ADD_LOCAL_S32_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, False, ),
2738 'IEM_MC_ADD_LOCAL_S64_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, False, ),
2739 'IEM_MC_ADVANCE_RIP_AND_FINISH': (McBlock.parseMcGeneric, True, True, ),
2740 'IEM_MC_AND_2LOCS_U32': (McBlock.parseMcGeneric, False, False, ),
2741 'IEM_MC_AND_ARG_U16': (McBlock.parseMcGeneric, False, False, ),
2742 'IEM_MC_AND_ARG_U32': (McBlock.parseMcGeneric, False, False, ),
2743 'IEM_MC_AND_ARG_U64': (McBlock.parseMcGeneric, False, False, ),
2744 'IEM_MC_AND_GREG_U16': (McBlock.parseMcGeneric, True, False, ),
2745 'IEM_MC_AND_GREG_U32': (McBlock.parseMcGeneric, True, False, ),
2746 'IEM_MC_AND_GREG_U64': (McBlock.parseMcGeneric, True, False, ),
2747 'IEM_MC_AND_GREG_U8': (McBlock.parseMcGeneric, True, False, ),
2748 'IEM_MC_AND_LOCAL_U16': (McBlock.parseMcGeneric, False, False, ),
2749 'IEM_MC_AND_LOCAL_U32': (McBlock.parseMcGeneric, False, False, ),
2750 'IEM_MC_AND_LOCAL_U64': (McBlock.parseMcGeneric, False, False, ),
2751 'IEM_MC_AND_LOCAL_U8': (McBlock.parseMcGeneric, False, False, ),
2752 'IEM_MC_ARG': (McBlock.parseMcArg, False, True, ),
2753 'IEM_MC_ARG_CONST': (McBlock.parseMcArgConst, False, True, ),
2754 'IEM_MC_ARG_LOCAL_EFLAGS': (McBlock.parseMcArgLocalEFlags, False, True, ),
2755 'IEM_MC_ARG_LOCAL_REF': (McBlock.parseMcArgLocalRef, False, True, ),
2756 'IEM_MC_ASSIGN_TO_SMALLER': (McBlock.parseMcGeneric, False, False, ),
2757 'IEM_MC_BEGIN': (McBlock.parseMcBegin, False, True, ),
2758 'IEM_MC_BROADCAST_XREG_U16_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2759 'IEM_MC_BROADCAST_XREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2760 'IEM_MC_BROADCAST_XREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2761 'IEM_MC_BROADCAST_XREG_U8_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2762 'IEM_MC_BROADCAST_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2763 'IEM_MC_BROADCAST_YREG_U16_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2764 'IEM_MC_BROADCAST_YREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2765 'IEM_MC_BROADCAST_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2766 'IEM_MC_BROADCAST_YREG_U8_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2767 'IEM_MC_BSWAP_LOCAL_U16': (McBlock.parseMcGeneric, False, False, ),
2768 'IEM_MC_BSWAP_LOCAL_U32': (McBlock.parseMcGeneric, False, False, ),
2769 'IEM_MC_BSWAP_LOCAL_U64': (McBlock.parseMcGeneric, False, False, ),
2770 'IEM_MC_CALC_RM_EFF_ADDR': (McBlock.parseMcGeneric, False, False, ),
2771 'IEM_MC_CALL_AIMPL_3': (McBlock.parseMcCallAImpl, True, False, ),
2772 'IEM_MC_CALL_AIMPL_4': (McBlock.parseMcCallAImpl, True, False, ),
2773 'IEM_MC_CALL_AVX_AIMPL_2': (McBlock.parseMcCallAvxAImpl, True, False, ),
2774 'IEM_MC_CALL_AVX_AIMPL_3': (McBlock.parseMcCallAvxAImpl, True, False, ),
2775 'IEM_MC_CALL_CIMPL_0': (McBlock.parseMcCallCImpl, True, False, ),
2776 'IEM_MC_CALL_CIMPL_1': (McBlock.parseMcCallCImpl, True, False, ),
2777 'IEM_MC_CALL_CIMPL_2': (McBlock.parseMcCallCImpl, True, False, ),
2778 'IEM_MC_CALL_CIMPL_3': (McBlock.parseMcCallCImpl, True, False, ),
2779 'IEM_MC_CALL_CIMPL_4': (McBlock.parseMcCallCImpl, True, False, ),
2780 'IEM_MC_CALL_CIMPL_5': (McBlock.parseMcCallCImpl, True, False, ),
2781 'IEM_MC_CALL_FPU_AIMPL_1': (McBlock.parseMcCallFpuAImpl, True, False, ),
2782 'IEM_MC_CALL_FPU_AIMPL_2': (McBlock.parseMcCallFpuAImpl, True, False, ),
2783 'IEM_MC_CALL_FPU_AIMPL_3': (McBlock.parseMcCallFpuAImpl, True, False, ),
2784 'IEM_MC_CALL_MMX_AIMPL_2': (McBlock.parseMcCallMmxAImpl, True, False, ),
2785 'IEM_MC_CALL_MMX_AIMPL_3': (McBlock.parseMcCallMmxAImpl, True, False, ),
2786 'IEM_MC_CALL_SSE_AIMPL_2': (McBlock.parseMcCallSseAImpl, True, False, ),
2787 'IEM_MC_CALL_SSE_AIMPL_3': (McBlock.parseMcCallSseAImpl, True, False, ),
2788 'IEM_MC_CALL_VOID_AIMPL_0': (McBlock.parseMcCallVoidAImpl, True, False, ),
2789 'IEM_MC_CALL_VOID_AIMPL_1': (McBlock.parseMcCallVoidAImpl, True, False, ),
2790 'IEM_MC_CALL_VOID_AIMPL_2': (McBlock.parseMcCallVoidAImpl, True, False, ),
2791 'IEM_MC_CALL_VOID_AIMPL_3': (McBlock.parseMcCallVoidAImpl, True, False, ),
2792 'IEM_MC_CALL_VOID_AIMPL_4': (McBlock.parseMcCallVoidAImpl, True, False, ),
2793 'IEM_MC_CLEAR_EFL_BIT': (McBlock.parseMcGeneric, True, False, ),
2794 'IEM_MC_CLEAR_FSW_EX': (McBlock.parseMcGeneric, True, False, ),
2795 'IEM_MC_CLEAR_HIGH_GREG_U64': (McBlock.parseMcGeneric, True, False, ),
2796 'IEM_MC_CLEAR_XREG_U32_MASK': (McBlock.parseMcGeneric, True, False, ),
2797 'IEM_MC_CLEAR_YREG_128_UP': (McBlock.parseMcGeneric, True, False, ),
2798 'IEM_MC_COMMIT_EFLAGS': (McBlock.parseMcGeneric, True, False, ),
2799 'IEM_MC_COPY_XREG_U128': (McBlock.parseMcGeneric, True, False, ),
2800 'IEM_MC_COPY_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2801 'IEM_MC_COPY_YREG_U256_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2802 'IEM_MC_COPY_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2803 'IEM_MC_DEFER_TO_CIMPL_0_RET': (McBlock.parseMcDeferToCImpl, False, False, ),
2804 'IEM_MC_DEFER_TO_CIMPL_1_RET': (McBlock.parseMcDeferToCImpl, False, False, ),
2805 'IEM_MC_DEFER_TO_CIMPL_2_RET': (McBlock.parseMcDeferToCImpl, False, False, ),
2806 'IEM_MC_DEFER_TO_CIMPL_3_RET': (McBlock.parseMcDeferToCImpl, False, False, ),
2807 'IEM_MC_END': (McBlock.parseMcGeneric, True, True, ),
2808 'IEM_MC_FETCH_EFLAGS': (McBlock.parseMcGeneric, False, False, ),
2809 'IEM_MC_FETCH_EFLAGS_U8': (McBlock.parseMcGeneric, False, False, ),
2810 'IEM_MC_FETCH_FCW': (McBlock.parseMcGeneric, False, False, ),
2811 'IEM_MC_FETCH_FSW': (McBlock.parseMcGeneric, False, False, ),
2812 'IEM_MC_FETCH_GREG_U16': (McBlock.parseMcGeneric, False, True, ),
2813 'IEM_MC_FETCH_GREG_U16_SX_U32': (McBlock.parseMcGeneric, False, False, ),
2814 'IEM_MC_FETCH_GREG_U16_SX_U64': (McBlock.parseMcGeneric, False, False, ),
2815 'IEM_MC_FETCH_GREG_U16_ZX_U32': (McBlock.parseMcGeneric, False, False, ),
2816 'IEM_MC_FETCH_GREG_U16_ZX_U64': (McBlock.parseMcGeneric, False, False, ),
2817 'IEM_MC_FETCH_GREG_U32': (McBlock.parseMcGeneric, False, True, ),
2818 'IEM_MC_FETCH_GREG_U32_SX_U64': (McBlock.parseMcGeneric, False, False, ),
2819 'IEM_MC_FETCH_GREG_U32_ZX_U64': (McBlock.parseMcGeneric, False, False, ),
2820 'IEM_MC_FETCH_GREG_U64': (McBlock.parseMcGeneric, False, False, ),
2821 'IEM_MC_FETCH_GREG_U64_ZX_U64': (McBlock.parseMcGeneric, False, False, ),
2822 'IEM_MC_FETCH_GREG_U8': (McBlock.parseMcGeneric, False, False, ),
2823 'IEM_MC_FETCH_GREG_U8_SX_U16': (McBlock.parseMcGeneric, False, False, ),
2824 'IEM_MC_FETCH_GREG_U8_SX_U32': (McBlock.parseMcGeneric, False, False, ),
2825 'IEM_MC_FETCH_GREG_U8_SX_U64': (McBlock.parseMcGeneric, False, False, ),
2826 'IEM_MC_FETCH_GREG_U8_ZX_U16': (McBlock.parseMcGeneric, False, False, ),
2827 'IEM_MC_FETCH_GREG_U8_ZX_U32': (McBlock.parseMcGeneric, False, False, ),
2828 'IEM_MC_FETCH_GREG_U8_ZX_U64': (McBlock.parseMcGeneric, False, False, ),
2829 'IEM_MC_FETCH_GREG_PAIR_U32': (McBlock.parseMcGeneric, False, False, ),
2830 'IEM_MC_FETCH_GREG_PAIR_U64': (McBlock.parseMcGeneric, False, False, ),
2831 'IEM_MC_FETCH_MEM_D80': (McBlock.parseMcGeneric, True, False, ),
2832 'IEM_MC_FETCH_MEM_I16': (McBlock.parseMcGeneric, True, False, ),
2833 'IEM_MC_FETCH_MEM_I32': (McBlock.parseMcGeneric, True, False, ),
2834 'IEM_MC_FETCH_MEM_I64': (McBlock.parseMcGeneric, True, False, ),
2835 'IEM_MC_FETCH_MEM_R32': (McBlock.parseMcGeneric, True, False, ),
2836 'IEM_MC_FETCH_MEM_R64': (McBlock.parseMcGeneric, True, False, ),
2837 'IEM_MC_FETCH_MEM_R80': (McBlock.parseMcGeneric, True, False, ),
2838 'IEM_MC_FETCH_MEM_S32_SX_U64': (McBlock.parseMcGeneric, True, False, ),
2839 'IEM_MC_FETCH_MEM_U128': (McBlock.parseMcGeneric, True, False, ),
2840 'IEM_MC_FETCH_MEM_U128_ALIGN_SSE': (McBlock.parseMcGeneric, True, False, ),
2841 'IEM_MC_FETCH_MEM_U128_NO_AC': (McBlock.parseMcGeneric, True, False, ),
2842 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128': (McBlock.parseMcGeneric, True, False, ),
2843 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_RAX_RDX_U64': (McBlock.parseMcGeneric, True, False, ),
2844 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_EAX_EDX_U32_SX_U64':(McBlock.parseMcGeneric, True, False, ),
2845 'IEM_MC_FETCH_MEM_U16': (McBlock.parseMcGeneric, True, False, ),
2846 'IEM_MC_FETCH_MEM_U16_DISP': (McBlock.parseMcGeneric, True, False, ),
2847 'IEM_MC_FETCH_MEM_U16_SX_U32': (McBlock.parseMcGeneric, True, False, ),
2848 'IEM_MC_FETCH_MEM_U16_SX_U64': (McBlock.parseMcGeneric, True, False, ),
2849 'IEM_MC_FETCH_MEM_U16_ZX_U32': (McBlock.parseMcGeneric, True, False, ),
2850 'IEM_MC_FETCH_MEM_U16_ZX_U64': (McBlock.parseMcGeneric, True, False, ),
2851 'IEM_MC_FETCH_MEM_U256': (McBlock.parseMcGeneric, True, False, ),
2852 'IEM_MC_FETCH_MEM_U256_ALIGN_AVX': (McBlock.parseMcGeneric, True, False, ),
2853 'IEM_MC_FETCH_MEM_U256_NO_AC': (McBlock.parseMcGeneric, True, False, ),
2854 'IEM_MC_FETCH_MEM_U32': (McBlock.parseMcGeneric, True, False, ),
2855 'IEM_MC_FETCH_MEM_U32_DISP': (McBlock.parseMcGeneric, True, False, ),
2856 'IEM_MC_FETCH_MEM_U32_SX_U64': (McBlock.parseMcGeneric, True, False, ),
2857 'IEM_MC_FETCH_MEM_U32_ZX_U64': (McBlock.parseMcGeneric, True, False, ),
2858 'IEM_MC_FETCH_MEM_U64': (McBlock.parseMcGeneric, True, False, ),
2859 'IEM_MC_FETCH_MEM_U64_ALIGN_U128': (McBlock.parseMcGeneric, True, False, ),
2860 'IEM_MC_FETCH_MEM_U64_DISP': (McBlock.parseMcGeneric, True, False, ),
2861 'IEM_MC_FETCH_MEM_U8': (McBlock.parseMcGeneric, True, False, ),
2862 'IEM_MC_FETCH_MEM_U8_SX_U16': (McBlock.parseMcGeneric, True, False, ),
2863 'IEM_MC_FETCH_MEM_U8_SX_U32': (McBlock.parseMcGeneric, True, False, ),
2864 'IEM_MC_FETCH_MEM_U8_SX_U64': (McBlock.parseMcGeneric, True, False, ),
2865 'IEM_MC_FETCH_MEM_U8_ZX_U16': (McBlock.parseMcGeneric, True, False, ),
2866 'IEM_MC_FETCH_MEM_U8_ZX_U32': (McBlock.parseMcGeneric, True, False, ),
2867 'IEM_MC_FETCH_MEM_U8_ZX_U64': (McBlock.parseMcGeneric, True, False, ),
2868 'IEM_MC_FETCH_MEM_XMM': (McBlock.parseMcGeneric, True, False, ),
2869 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE': (McBlock.parseMcGeneric, True, False, ),
2870 'IEM_MC_FETCH_MEM_XMM_NO_AC': (McBlock.parseMcGeneric, True, False, ),
2871 'IEM_MC_FETCH_MEM_XMM_U32': (McBlock.parseMcGeneric, True, False, ),
2872 'IEM_MC_FETCH_MEM_XMM_U64': (McBlock.parseMcGeneric, True, False, ),
2873 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE_AND_XREG_XMM': (McBlock.parseMcGeneric, True, False, ),
2874 'IEM_MC_FETCH_MEM_XMM_U32_AND_XREG_XMM': (McBlock.parseMcGeneric, True, False, ),
2875 'IEM_MC_FETCH_MEM_XMM_U64_AND_XREG_XMM': (McBlock.parseMcGeneric, True, False, ),
2876 'IEM_MC_FETCH_MEM_YMM': (McBlock.parseMcGeneric, True, False, ),
2877 'IEM_MC_FETCH_MEM_YMM_ALIGN_AVX': (McBlock.parseMcGeneric, True, False, ),
2878 'IEM_MC_FETCH_MEM_YMM_NO_AC': (McBlock.parseMcGeneric, True, False, ),
2879 'IEM_MC_FETCH_MEM16_U8': (McBlock.parseMcGeneric, True, False, ),
2880 'IEM_MC_FETCH_MEM32_U8': (McBlock.parseMcGeneric, True, False, ),
2881 'IEM_MC_FETCH_MREG_U32': (McBlock.parseMcGeneric, False, False, ),
2882 'IEM_MC_FETCH_MREG_U64': (McBlock.parseMcGeneric, False, False, ),
2883 'IEM_MC_FETCH_SREG_BASE_U32': (McBlock.parseMcGeneric, False, False, ),
2884 'IEM_MC_FETCH_SREG_BASE_U64': (McBlock.parseMcGeneric, False, False, ),
2885 'IEM_MC_FETCH_SREG_U16': (McBlock.parseMcGeneric, False, False, ),
2886 'IEM_MC_FETCH_SREG_ZX_U32': (McBlock.parseMcGeneric, False, False, ),
2887 'IEM_MC_FETCH_SREG_ZX_U64': (McBlock.parseMcGeneric, False, False, ),
2888 'IEM_MC_FETCH_XREG_U128': (McBlock.parseMcGeneric, False, False, ),
2889 'IEM_MC_FETCH_XREG_U16': (McBlock.parseMcGeneric, False, False, ),
2890 'IEM_MC_FETCH_XREG_U32': (McBlock.parseMcGeneric, False, False, ),
2891 'IEM_MC_FETCH_XREG_U64': (McBlock.parseMcGeneric, False, False, ),
2892 'IEM_MC_FETCH_XREG_U8': (McBlock.parseMcGeneric, False, False, ),
2893 'IEM_MC_FETCH_XREG_XMM': (McBlock.parseMcGeneric, False, False, ),
2894 'IEM_MC_FETCH_XREG_PAIR_U128': (McBlock.parseMcGeneric, False, False, ),
2895 'IEM_MC_FETCH_XREG_PAIR_U128_AND_RAX_RDX_U64': (McBlock.parseMcGeneric, False, False, ),
2896 'IEM_MC_FETCH_XREG_PAIR_U128_AND_EAX_EDX_U32_SX_U64': (McBlock.parseMcGeneric, False, False, ),
2897 'IEM_MC_FETCH_XREG_PAIR_XMM': (McBlock.parseMcGeneric, False, False, ),
2898 'IEM_MC_FETCH_YREG_2ND_U64': (McBlock.parseMcGeneric, False, False, ),
2899 'IEM_MC_FETCH_YREG_U128': (McBlock.parseMcGeneric, False, False, ),
2900 'IEM_MC_FETCH_YREG_U256': (McBlock.parseMcGeneric, False, False, ),
2901 'IEM_MC_FETCH_YREG_U32': (McBlock.parseMcGeneric, False, False, ),
2902 'IEM_MC_FETCH_YREG_U64': (McBlock.parseMcGeneric, False, False, ),
2903 'IEM_MC_FLIP_EFL_BIT': (McBlock.parseMcGeneric, True, False, ),
2904 'IEM_MC_FPU_FROM_MMX_MODE': (McBlock.parseMcGeneric, True, False, ),
2905 'IEM_MC_FPU_STACK_DEC_TOP': (McBlock.parseMcGeneric, True, False, ),
2906 'IEM_MC_FPU_STACK_FREE': (McBlock.parseMcGeneric, True, False, ),
2907 'IEM_MC_FPU_STACK_INC_TOP': (McBlock.parseMcGeneric, True, False, ),
2908 'IEM_MC_FPU_STACK_PUSH_OVERFLOW': (McBlock.parseMcGeneric, True, False, ),
2909 'IEM_MC_FPU_STACK_PUSH_OVERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, False, ),
2910 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW': (McBlock.parseMcGeneric, True, False, ),
2911 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW_TWO': (McBlock.parseMcGeneric, True, False, ),
2912 'IEM_MC_FPU_STACK_UNDERFLOW': (McBlock.parseMcGeneric, True, False, ),
2913 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, False, ),
2914 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, False, ),
2915 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP': (McBlock.parseMcGeneric, True, False, ),
2916 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP_POP': (McBlock.parseMcGeneric, True, False, ),
2917 'IEM_MC_FPU_TO_MMX_MODE': (McBlock.parseMcGeneric, True, False, ),
2918 'IEM_MC_HINT_FLUSH_GUEST_SHADOW': (McBlock.parseMcGeneric, True, True, ),
2919 'IEM_MC_IF_CX_IS_NZ': (McBlock.parseMcGenericCond, True, True, ),
2920 'IEM_MC_IF_CX_IS_NZ_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, True, ),
2921 'IEM_MC_IF_CX_IS_NZ_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, True, ),
2922 'IEM_MC_IF_ECX_IS_NZ': (McBlock.parseMcGenericCond, True, True, ),
2923 'IEM_MC_IF_ECX_IS_NZ_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, True, ),
2924 'IEM_MC_IF_ECX_IS_NZ_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, True, ),
2925 'IEM_MC_IF_EFL_ANY_BITS_SET': (McBlock.parseMcGenericCond, True, True, ),
2926 'IEM_MC_IF_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, True, ),
2927 'IEM_MC_IF_EFL_BIT_NOT_SET_AND_BITS_EQ': (McBlock.parseMcGenericCond, True, True, ),
2928 'IEM_MC_IF_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, True, ),
2929 'IEM_MC_IF_EFL_BIT_SET_OR_BITS_NE': (McBlock.parseMcGenericCond, True, True, ),
2930 'IEM_MC_IF_EFL_BITS_EQ': (McBlock.parseMcGenericCond, True, True, ),
2931 'IEM_MC_IF_EFL_BITS_NE': (McBlock.parseMcGenericCond, True, True, ),
2932 'IEM_MC_IF_EFL_NO_BITS_SET': (McBlock.parseMcGenericCond, True, True, ),
2933 'IEM_MC_IF_FCW_IM': (McBlock.parseMcGenericCond, True, False, ),
2934 'IEM_MC_IF_FPUREG_IS_EMPTY': (McBlock.parseMcGenericCond, True, False, ),
2935 'IEM_MC_IF_FPUREG_NOT_EMPTY': (McBlock.parseMcGenericCond, True, False, ),
2936 'IEM_MC_IF_FPUREG_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, False, ),
2937 'IEM_MC_IF_GREG_BIT_SET': (McBlock.parseMcGenericCond, True, False, ),
2938 'IEM_MC_IF_LOCAL_IS_Z': (McBlock.parseMcGenericCond, True, False, ),
2939 'IEM_MC_IF_MXCSR_XCPT_PENDING': (McBlock.parseMcGenericCond, True, False, ),
2940 'IEM_MC_IF_RCX_IS_NZ': (McBlock.parseMcGenericCond, True, True, ),
2941 'IEM_MC_IF_RCX_IS_NZ_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, True, ),
2942 'IEM_MC_IF_RCX_IS_NZ_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, True, ),
2943 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, False, ),
2944 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80_FIRST': (McBlock.parseMcGenericCond, True, False, ),
2945 'IEM_MC_IMPLICIT_AVX_AIMPL_ARGS': (McBlock.parseMcImplicitAvxAArgs, False, False, ),
2946 'IEM_MC_INT_CLEAR_ZMM_256_UP': (McBlock.parseMcGeneric, True, False, ),
2947 'IEM_MC_LOCAL': (McBlock.parseMcLocal, False, True, ),
2948 'IEM_MC_LOCAL_ASSIGN': (McBlock.parseMcLocalAssign, False, True, ),
2949 'IEM_MC_LOCAL_CONST': (McBlock.parseMcLocalConst, False, True, ),
2950 'IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT': (McBlock.parseMcGeneric, True, False, ),
2951 'IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, False, ),
2952 'IEM_MC_MAYBE_RAISE_FPU_XCPT': (McBlock.parseMcGeneric, True, False, ),
2953 'IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT': (McBlock.parseMcGeneric, True, False, ),
2954 'IEM_MC_MAYBE_RAISE_MMX_RELATED_XCPT': (McBlock.parseMcGeneric, True, False, ),
2955 'IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0': (McBlock.parseMcGeneric, True, False, ),
2956 'IEM_MC_MAYBE_RAISE_SSE_AVX_SIMD_FP_OR_UD_XCPT': (McBlock.parseMcGeneric, True, False, ),
2957 'IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT': (McBlock.parseMcGeneric, True, False, ),
2958 'IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, False, ),
2959 'IEM_MC_MEM_COMMIT_AND_UNMAP': (McBlock.parseMcGeneric, True, False, ),
2960 'IEM_MC_MEM_COMMIT_AND_UNMAP_RW': (McBlock.parseMcGeneric, True, False, ),
2961 'IEM_MC_MEM_COMMIT_AND_UNMAP_RO': (McBlock.parseMcGeneric, True, False, ),
2962 'IEM_MC_MEM_COMMIT_AND_UNMAP_WO': (McBlock.parseMcGeneric, True, False, ),
2963 'IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE': (McBlock.parseMcGeneric, True, False, ),
2964 'IEM_MC_MEM_MAP': (McBlock.parseMcGeneric, True, False, ),
2965 'IEM_MC_MEM_MAP_EX': (McBlock.parseMcGeneric, True, False, ),
2966 'IEM_MC_MEM_MAP_U8_RW': (McBlock.parseMcGeneric, True, False, ),
2967 'IEM_MC_MEM_MAP_U8_RO': (McBlock.parseMcGeneric, True, False, ),
2968 'IEM_MC_MEM_MAP_U8_WO': (McBlock.parseMcGeneric, True, False, ),
2969 'IEM_MC_MEM_MAP_U16_RW': (McBlock.parseMcGeneric, True, False, ),
2970 'IEM_MC_MEM_MAP_U16_RO': (McBlock.parseMcGeneric, True, False, ),
2971 'IEM_MC_MEM_MAP_U16_WO': (McBlock.parseMcGeneric, True, False, ),
2972 'IEM_MC_MEM_MAP_U32_RW': (McBlock.parseMcGeneric, True, False, ),
2973 'IEM_MC_MEM_MAP_U32_RO': (McBlock.parseMcGeneric, True, False, ),
2974 'IEM_MC_MEM_MAP_U32_WO': (McBlock.parseMcGeneric, True, False, ),
2975 'IEM_MC_MEM_MAP_U64_RW': (McBlock.parseMcGeneric, True, False, ),
2976 'IEM_MC_MEM_MAP_U64_RO': (McBlock.parseMcGeneric, True, False, ),
2977 'IEM_MC_MEM_MAP_U64_WO': (McBlock.parseMcGeneric, True, False, ),
2978 'IEM_MC_MERGE_YREG_U32_U96_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2979 'IEM_MC_MERGE_YREG_U64_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2980 'IEM_MC_MERGE_YREG_U64HI_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2981 'IEM_MC_MERGE_YREG_U64LO_U64LO_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2982 'IEM_MC_MERGE_YREG_U64LO_U64LOCAL_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2983 'IEM_MC_MERGE_YREG_U64LOCAL_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
2984 'IEM_MC_MODIFIED_MREG': (McBlock.parseMcGeneric, True, False, ),
2985 'IEM_MC_MODIFIED_MREG_BY_REF': (McBlock.parseMcGeneric, True, False, ),
2986 'IEM_MC_OR_2LOCS_U32': (McBlock.parseMcGeneric, False, False, ),
2987 'IEM_MC_OR_GREG_U16': (McBlock.parseMcGeneric, True, False, ),
2988 'IEM_MC_OR_GREG_U32': (McBlock.parseMcGeneric, True, False, ),
2989 'IEM_MC_OR_GREG_U64': (McBlock.parseMcGeneric, True, False, ),
2990 'IEM_MC_OR_GREG_U8': (McBlock.parseMcGeneric, True, False, ),
2991 'IEM_MC_OR_LOCAL_U16': (McBlock.parseMcGeneric, False, False, ),
2992 'IEM_MC_OR_LOCAL_U32': (McBlock.parseMcGeneric, False, False, ),
2993 'IEM_MC_OR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, ),
2994 'IEM_MC_POP_U16': (McBlock.parseMcGeneric, True, False, ),
2995 'IEM_MC_POP_U32': (McBlock.parseMcGeneric, True, False, ),
2996 'IEM_MC_POP_U64': (McBlock.parseMcGeneric, True, False, ),
2997 'IEM_MC_PREPARE_AVX_USAGE': (McBlock.parseMcGeneric, False, False, ),
2998 'IEM_MC_PREPARE_FPU_USAGE': (McBlock.parseMcGeneric, False, False, ),
2999 'IEM_MC_PREPARE_SSE_USAGE': (McBlock.parseMcGeneric, False, False, ),
3000 'IEM_MC_PUSH_FPU_RESULT': (McBlock.parseMcGeneric, True, False, ),
3001 'IEM_MC_PUSH_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, False, ),
3002 'IEM_MC_PUSH_FPU_RESULT_TWO': (McBlock.parseMcGeneric, True, False, ),
3003 'IEM_MC_PUSH_U16': (McBlock.parseMcGeneric, True, False, ),
3004 'IEM_MC_PUSH_U32': (McBlock.parseMcGeneric, True, False, ),
3005 'IEM_MC_PUSH_U32_SREG': (McBlock.parseMcGeneric, True, False, ),
3006 'IEM_MC_PUSH_U64': (McBlock.parseMcGeneric, True, False, ),
3007 'IEM_MC_RAISE_DIVIDE_ERROR': (McBlock.parseMcGeneric, True, False, ),
3008 'IEM_MC_RAISE_GP0_IF_CPL_NOT_ZERO': (McBlock.parseMcGeneric, True, False, ),
3009 'IEM_MC_RAISE_GP0_IF_EFF_ADDR_UNALIGNED': (McBlock.parseMcGeneric, True, False, ),
3010 'IEM_MC_RAISE_SSE_AVX_SIMD_FP_OR_UD_XCPT': (McBlock.parseMcGeneric, True, False, ),
3011 'IEM_MC_REF_EFLAGS': (McBlock.parseMcGeneric, False, False, ),
3012 'IEM_MC_REF_FPUREG': (McBlock.parseMcGeneric, False, False, ),
3013 'IEM_MC_REF_GREG_I32': (McBlock.parseMcGeneric, False, False, ),
3014 'IEM_MC_REF_GREG_I32_CONST': (McBlock.parseMcGeneric, False, False, ),
3015 'IEM_MC_REF_GREG_I64': (McBlock.parseMcGeneric, False, False, ),
3016 'IEM_MC_REF_GREG_I64_CONST': (McBlock.parseMcGeneric, False, False, ),
3017 'IEM_MC_REF_GREG_U16': (McBlock.parseMcGeneric, False, False, ),
3018 'IEM_MC_REF_GREG_U16_CONST': (McBlock.parseMcGeneric, False, False, ),
3019 'IEM_MC_REF_GREG_U32': (McBlock.parseMcGeneric, False, False, ),
3020 'IEM_MC_REF_GREG_U32_CONST': (McBlock.parseMcGeneric, False, False, ),
3021 'IEM_MC_REF_GREG_U64': (McBlock.parseMcGeneric, False, False, ),
3022 'IEM_MC_REF_GREG_U64_CONST': (McBlock.parseMcGeneric, False, False, ),
3023 'IEM_MC_REF_GREG_U8': (McBlock.parseMcGeneric, False, False, ),
3024 'IEM_MC_REF_GREG_U8_CONST': (McBlock.parseMcGeneric, False, False, ),
3025 'IEM_MC_REF_LOCAL': (McBlock.parseMcGeneric, False, False, ),
3026 'IEM_MC_REF_MREG_U32_CONST': (McBlock.parseMcGeneric, False, False, ),
3027 'IEM_MC_REF_MREG_U64': (McBlock.parseMcGeneric, False, False, ),
3028 'IEM_MC_REF_MREG_U64_CONST': (McBlock.parseMcGeneric, False, False, ),
3029 'IEM_MC_REF_MXCSR': (McBlock.parseMcGeneric, False, False, ),
3030 'IEM_MC_REF_XREG_R32_CONST': (McBlock.parseMcGeneric, False, False, ),
3031 'IEM_MC_REF_XREG_R64_CONST': (McBlock.parseMcGeneric, False, False, ),
3032 'IEM_MC_REF_XREG_U128': (McBlock.parseMcGeneric, False, False, ),
3033 'IEM_MC_REF_XREG_U128_CONST': (McBlock.parseMcGeneric, False, False, ),
3034 'IEM_MC_REF_XREG_U32_CONST': (McBlock.parseMcGeneric, False, False, ),
3035 'IEM_MC_REF_XREG_U64_CONST': (McBlock.parseMcGeneric, False, False, ),
3036 'IEM_MC_REF_XREG_XMM_CONST': (McBlock.parseMcGeneric, False, False, ),
3037 'IEM_MC_REF_YREG_U128': (McBlock.parseMcGeneric, False, False, ),
3038 'IEM_MC_REF_YREG_U128_CONST': (McBlock.parseMcGeneric, False, False, ),
3039 'IEM_MC_REF_YREG_U64_CONST': (McBlock.parseMcGeneric, False, False, ),
3040 'IEM_MC_REL_JMP_S16_AND_FINISH': (McBlock.parseMcGeneric, True, False, ),
3041 'IEM_MC_REL_JMP_S32_AND_FINISH': (McBlock.parseMcGeneric, True, False, ),
3042 'IEM_MC_REL_JMP_S8_AND_FINISH': (McBlock.parseMcGeneric, True, False, ),
3043 'IEM_MC_RETURN_ON_FAILURE': (McBlock.parseMcGeneric, False, False, ),
3044 'IEM_MC_SAR_LOCAL_S16': (McBlock.parseMcGeneric, False, False, ),
3045 'IEM_MC_SAR_LOCAL_S32': (McBlock.parseMcGeneric, False, False, ),
3046 'IEM_MC_SAR_LOCAL_S64': (McBlock.parseMcGeneric, False, False, ),
3047 'IEM_MC_SET_EFL_BIT': (McBlock.parseMcGeneric, True, False, ),
3048 'IEM_MC_SET_FPU_RESULT': (McBlock.parseMcGeneric, True, False, ),
3049 'IEM_MC_SET_RIP_U16_AND_FINISH': (McBlock.parseMcGeneric, True, False, ),
3050 'IEM_MC_SET_RIP_U32_AND_FINISH': (McBlock.parseMcGeneric, True, False, ),
3051 'IEM_MC_SET_RIP_U64_AND_FINISH': (McBlock.parseMcGeneric, True, False, ),
3052 'IEM_MC_SHL_LOCAL_S16': (McBlock.parseMcGeneric, False, False, ),
3053 'IEM_MC_SHL_LOCAL_S32': (McBlock.parseMcGeneric, False, False, ),
3054 'IEM_MC_SHL_LOCAL_S64': (McBlock.parseMcGeneric, False, False, ),
3055 'IEM_MC_SHR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, ),
3056 'IEM_MC_SSE_UPDATE_MXCSR': (McBlock.parseMcGeneric, True, False, ),
3057 'IEM_MC_STORE_FPU_RESULT': (McBlock.parseMcGeneric, True, False, ),
3058 'IEM_MC_STORE_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, False, ),
3059 'IEM_MC_STORE_FPU_RESULT_THEN_POP': (McBlock.parseMcGeneric, True, False, ),
3060 'IEM_MC_STORE_FPU_RESULT_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, False, ),
3061 'IEM_MC_STORE_FPUREG_R80_SRC_REF': (McBlock.parseMcGeneric, True, False, ),
3062 'IEM_MC_STORE_GREG_I64': (McBlock.parseMcGeneric, True, False, ),
3063 'IEM_MC_STORE_GREG_U16': (McBlock.parseMcGeneric, True, True, ),
3064 'IEM_MC_STORE_GREG_U16_CONST': (McBlock.parseMcGeneric, True, True, ),
3065 'IEM_MC_STORE_GREG_U32': (McBlock.parseMcGeneric, True, True, ),
3066 'IEM_MC_STORE_GREG_U32_CONST': (McBlock.parseMcGeneric, True, True, ),
3067 'IEM_MC_STORE_GREG_U64': (McBlock.parseMcGeneric, True, False, ),
3068 'IEM_MC_STORE_GREG_U64_CONST': (McBlock.parseMcGeneric, True, False, ),
3069 'IEM_MC_STORE_GREG_U8': (McBlock.parseMcGeneric, True, False, ),
3070 'IEM_MC_STORE_GREG_U8_CONST': (McBlock.parseMcGeneric, True, False, ),
3071 'IEM_MC_STORE_GREG_PAIR_U32': (McBlock.parseMcGeneric, True, False, ),
3072 'IEM_MC_STORE_GREG_PAIR_U64': (McBlock.parseMcGeneric, True, False, ),
3073 'IEM_MC_STORE_MEM_I16_CONST_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3074 'IEM_MC_STORE_MEM_I32_CONST_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3075 'IEM_MC_STORE_MEM_I64_CONST_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3076 'IEM_MC_STORE_MEM_I8_CONST_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3077 'IEM_MC_STORE_MEM_INDEF_D80_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3078 'IEM_MC_STORE_MEM_NEG_QNAN_R32_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3079 'IEM_MC_STORE_MEM_NEG_QNAN_R64_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3080 'IEM_MC_STORE_MEM_NEG_QNAN_R80_BY_REF': (McBlock.parseMcGeneric, True, False, ),
3081 'IEM_MC_STORE_MEM_U128': (McBlock.parseMcGeneric, True, False, ),
3082 'IEM_MC_STORE_MEM_U128_ALIGN_SSE': (McBlock.parseMcGeneric, True, False, ),
3083 'IEM_MC_STORE_MEM_U16': (McBlock.parseMcGeneric, True, False, ),
3084 'IEM_MC_STORE_MEM_U16_CONST': (McBlock.parseMcGeneric, True, False, ),
3085 'IEM_MC_STORE_MEM_U256': (McBlock.parseMcGeneric, True, False, ),
3086 'IEM_MC_STORE_MEM_U256_ALIGN_AVX': (McBlock.parseMcGeneric, True, False, ),
3087 'IEM_MC_STORE_MEM_U32': (McBlock.parseMcGeneric, True, False, ),
3088 'IEM_MC_STORE_MEM_U32_CONST': (McBlock.parseMcGeneric, True, False, ),
3089 'IEM_MC_STORE_MEM_U64': (McBlock.parseMcGeneric, True, False, ),
3090 'IEM_MC_STORE_MEM_U64_CONST': (McBlock.parseMcGeneric, True, False, ),
3091 'IEM_MC_STORE_MEM_U8': (McBlock.parseMcGeneric, True, False, ),
3092 'IEM_MC_STORE_MEM_U8_CONST': (McBlock.parseMcGeneric, True, False, ),
3093 'IEM_MC_STORE_MREG_U32_ZX_U64': (McBlock.parseMcGeneric, True, False, ),
3094 'IEM_MC_STORE_MREG_U64': (McBlock.parseMcGeneric, True, False, ),
3095 'IEM_MC_STORE_SREG_BASE_U32': (McBlock.parseMcGeneric, True, False, ),
3096 'IEM_MC_STORE_SREG_BASE_U64': (McBlock.parseMcGeneric, True, False, ),
3097 'IEM_MC_STORE_SSE_RESULT': (McBlock.parseMcGeneric, True, False, ),
3098 'IEM_MC_STORE_XREG_HI_U64': (McBlock.parseMcGeneric, True, False, ),
3099 'IEM_MC_STORE_XREG_R32': (McBlock.parseMcGeneric, True, False, ),
3100 'IEM_MC_STORE_XREG_R64': (McBlock.parseMcGeneric, True, False, ),
3101 'IEM_MC_STORE_XREG_U128': (McBlock.parseMcGeneric, True, False, ),
3102 'IEM_MC_STORE_XREG_U16': (McBlock.parseMcGeneric, True, False, ),
3103 'IEM_MC_STORE_XREG_U32': (McBlock.parseMcGeneric, True, False, ),
3104 'IEM_MC_STORE_XREG_U32_U128': (McBlock.parseMcGeneric, True, False, ),
3105 'IEM_MC_STORE_XREG_U32_ZX_U128': (McBlock.parseMcGeneric, True, False, ),
3106 'IEM_MC_STORE_XREG_U64': (McBlock.parseMcGeneric, True, False, ),
3107 'IEM_MC_STORE_XREG_U64_ZX_U128': (McBlock.parseMcGeneric, True, False, ),
3108 'IEM_MC_STORE_XREG_U8': (McBlock.parseMcGeneric, True, False, ),
3109 'IEM_MC_STORE_XREG_XMM': (McBlock.parseMcGeneric, True, False, ),
3110 'IEM_MC_STORE_XREG_XMM_U32': (McBlock.parseMcGeneric, True, False, ),
3111 'IEM_MC_STORE_XREG_XMM_U64': (McBlock.parseMcGeneric, True, False, ),
3112 'IEM_MC_STORE_YREG_U128': (McBlock.parseMcGeneric, True, False, ),
3113 'IEM_MC_STORE_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
3114 'IEM_MC_STORE_YREG_U256_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
3115 'IEM_MC_STORE_YREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
3116 'IEM_MC_STORE_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, False, ),
3117 'IEM_MC_SUB_GREG_U16': (McBlock.parseMcGeneric, True, True, ),
3118 'IEM_MC_SUB_GREG_U32': (McBlock.parseMcGeneric, True, True, ),
3119 'IEM_MC_SUB_GREG_U64': (McBlock.parseMcGeneric, True, True, ),
3120 'IEM_MC_SUB_LOCAL_U16': (McBlock.parseMcGeneric, False, False, ),
3121 'IEM_MC_UPDATE_FPU_OPCODE_IP': (McBlock.parseMcGeneric, True, False, ),
3122 'IEM_MC_UPDATE_FSW': (McBlock.parseMcGeneric, True, False, ),
3123 'IEM_MC_UPDATE_FSW_CONST': (McBlock.parseMcGeneric, True, False, ),
3124 'IEM_MC_UPDATE_FSW_THEN_POP': (McBlock.parseMcGeneric, True, False, ),
3125 'IEM_MC_UPDATE_FSW_THEN_POP_POP': (McBlock.parseMcGeneric, True, False, ),
3126 'IEM_MC_UPDATE_FSW_WITH_MEM_OP': (McBlock.parseMcGeneric, True, False, ),
3127 'IEM_MC_UPDATE_FSW_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, False, ),
3128 'IEM_MC_NO_NATIVE_RECOMPILE': (McBlock.parseMcGeneric, False, False, ),
3129};
3130
3131## List of microcode blocks.
3132g_aoMcBlocks = [] # type: List[McBlock]
3133
3134
3135
3136class ParserException(Exception):
3137 """ Parser exception """
3138 def __init__(self, sMessage):
3139 Exception.__init__(self, sMessage);
3140
3141
3142class SimpleParser(object): # pylint: disable=too-many-instance-attributes
3143 """
3144 Parser of IEMAllInstruction*.cpp.h instruction specifications.
3145 """
3146
3147 ## @name Parser state.
3148 ## @{
3149 kiCode = 0;
3150 kiCommentMulti = 1;
3151 ## @}
3152
3153 class Macro(object):
3154 """ Macro """
3155 def __init__(self, sName, asArgs, sBody, iLine):
3156 self.sName = sName; ##< The macro name.
3157 self.asArgs = asArgs; ##< None if simple macro, list of parameters otherwise.
3158 self.sBody = sBody;
3159 self.iLine = iLine;
3160 self.oReArgMatch = re.compile(r'(\s*##\s*|\b)(' + '|'.join(asArgs) + r')(\s*##\s*|\b)') if asArgs else None;
3161
3162 @staticmethod
3163 def _needSpace(ch):
3164 """ This is just to make the expanded output a bit prettier. """
3165 return ch.isspace() and ch != '(';
3166
3167 def expandMacro(self, oParent, asArgs = None):
3168 """ Expands the macro body with the given arguments. """
3169 _ = oParent;
3170 sBody = self.sBody;
3171
3172 if self.oReArgMatch:
3173 assert len(asArgs) == len(self.asArgs);
3174 #oParent.debug('%s: %s' % (self.sName, self.oReArgMatch.pattern,));
3175
3176 dArgs = { self.asArgs[iArg]: sValue for iArg, sValue in enumerate(asArgs) };
3177 oMatch = self.oReArgMatch.search(sBody);
3178 while oMatch:
3179 sName = oMatch.group(2);
3180 #oParent.debug('%s %s..%s (%s)' % (sName, oMatch.start(), oMatch.end(),oMatch.group()));
3181 sValue = dArgs[sName];
3182 sPre = '';
3183 if not oMatch.group(1) and oMatch.start() > 0 and self._needSpace(sBody[oMatch.start()]):
3184 sPre = ' ';
3185 sPost = '';
3186 if not oMatch.group(3) and oMatch.end() < len(sBody) and self._needSpace(sBody[oMatch.end()]):
3187 sPost = ' ';
3188 sBody = sBody[ : oMatch.start()] + sPre + sValue + sPost + sBody[oMatch.end() : ];
3189 oMatch = self.oReArgMatch.search(sBody, oMatch.start() + len(sValue));
3190 else:
3191 assert not asArgs;
3192
3193 return sBody;
3194
3195 class PreprocessorConditional(object):
3196 """ Preprocessor conditional (#if/#ifdef/#ifndef/#elif/#else/#endif). """
3197
3198 ## Known defines.
3199 # - A value of 1 indicates that it's always defined.
3200 # - A value of 0 if it's always undefined
3201 # - A value of -1 if it's an arch and it depends of script parameters.
3202 # - A value of -2 if it's not recognized when filtering MC blocks.
3203 kdKnownDefines = {
3204 'IEM_WITH_ONE_BYTE_TABLE': 1,
3205 'IEM_WITH_TWO_BYTE_TABLE': 1,
3206 'IEM_WITH_THREE_0F_38': 1,
3207 'IEM_WITH_THREE_0F_3A': 1,
3208 'IEM_WITH_THREE_BYTE_TABLES': 1,
3209 'IEM_WITH_3DNOW': 1,
3210 'IEM_WITH_3DNOW_TABLE': 1,
3211 'IEM_WITH_VEX': 1,
3212 'IEM_WITH_VEX_TABLES': 1,
3213 'VBOX_WITH_NESTED_HWVIRT_VMX': 1,
3214 'VBOX_WITH_NESTED_HWVIRT_VMX_EPT': 1,
3215 'VBOX_WITH_NESTED_HWVIRT_SVM': 1,
3216 'LOG_ENABLED': 1,
3217 'RT_WITHOUT_PRAGMA_ONCE': 0,
3218 'TST_IEM_CHECK_MC': 0,
3219 'IEM_WITHOUT_ASSEMBLY': -2, ##< @todo ??
3220 'RT_ARCH_AMD64': -1,
3221 'RT_ARCH_ARM64': -1,
3222 'RT_ARCH_ARM32': -1,
3223 'RT_ARCH_X86': -1,
3224 'RT_ARCH_SPARC': -1,
3225 'RT_ARCH_SPARC64': -1,
3226 };
3227 kdBuildArchToIprt = {
3228 'amd64': 'RT_ARCH_AMD64',
3229 'arm64': 'RT_ARCH_ARM64',
3230 'sparc32': 'RT_ARCH_SPARC64',
3231 };
3232 ## For parsing the next defined(xxxx).
3233 koMatchDefined = re.compile(r'\s*defined\s*\(\s*([^ \t)]+)\s*\)\s*');
3234
3235 def __init__(self, sType, sExpr):
3236 self.sType = sType;
3237 self.sExpr = sExpr; ##< Expression without command and no leading or trailing spaces.
3238 self.aoElif = [] # type: List[PreprocessorConditional]
3239 self.fInElse = [];
3240 if sType in ('if', 'elif'):
3241 self.checkExpression(sExpr);
3242 else:
3243 self.checkSupportedDefine(sExpr)
3244
3245 @staticmethod
3246 def checkSupportedDefine(sDefine):
3247 """ Checks that sDefine is one that we support. Raises exception if unuspported. """
3248 #print('debug: checkSupportedDefine: %s' % (sDefine,), file = sys.stderr);
3249 if sDefine in SimpleParser.PreprocessorConditional.kdKnownDefines:
3250 return True;
3251 if sDefine.startswith('VMM_INCLUDED_') and sDefine.endswith('_h'):
3252 return True;
3253 raise Exception('Unsupported define: %s' % (sDefine,));
3254
3255 @staticmethod
3256 def checkExpression(sExpr):
3257 """ Check that the expression is supported. Raises exception if not. """
3258 #print('debug: checkExpression: %s' % (sExpr,), file = sys.stderr);
3259 if sExpr in ('0', '1'):
3260 return True;
3261
3262 off = 0;
3263 cParan = 0;
3264 while off < len(sExpr):
3265 ch = sExpr[off];
3266
3267 # Unary operator or parentheses:
3268 if ch in ('(', '!'):
3269 if ch == '(':
3270 cParan += 1;
3271 off += 1;
3272 else:
3273 # defined(xxxx)
3274 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3275 if oMatch:
3276 SimpleParser.PreprocessorConditional.checkSupportedDefine(oMatch.group(1));
3277 elif sExpr[off:] != '1':
3278 raise Exception('Cannot grok: \'%s\' (at %u in: \'%s\')' % (sExpr[off:10], off + 1, sExpr,));
3279 off = oMatch.end();
3280
3281 # Look for closing parentheses.
3282 while off < len(sExpr) and sExpr[off].isspace():
3283 off += 1;
3284 if cParan > 0:
3285 while off < len(sExpr) and sExpr[off] == ')':
3286 if cParan <= 0:
3287 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3288 cParan -= 1;
3289 off += 1;
3290 while off < len(sExpr) and sExpr[off].isspace():
3291 off += 1;
3292
3293 # Look for binary operator.
3294 if off >= len(sExpr):
3295 break;
3296 if sExpr[off:off + 2] in ('||', '&&'):
3297 off += 2;
3298 else:
3299 raise Exception('Cannot grok operator: \'%s\' (at %u in: \'%s\')' % (sExpr[off:2], off + 1, sExpr,));
3300
3301 # Skip spaces.
3302 while off < len(sExpr) and sExpr[off].isspace():
3303 off += 1;
3304 if cParan != 0:
3305 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3306 return True;
3307
3308 @staticmethod
3309 def isArchIncludedInExpr(sExpr, sArch):
3310 """ Checks if sArch is included in the given expression. """
3311 # We only grok defined() [|| defined()...] and [1|0] at the moment.
3312 if sExpr == '0':
3313 return False;
3314 if sExpr == '1':
3315 return True;
3316 off = 0;
3317 while off < len(sExpr):
3318 # defined(xxxx)
3319 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3320 if not oMatch:
3321 if sExpr[off:] == '1':
3322 return True;
3323 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3324 if SimpleParser.PreprocessorConditional.matchDefined(oMatch.group(1), sArch):
3325 return True;
3326 off = oMatch.end();
3327
3328 # Look for OR operator.
3329 while off + 1 < len(sExpr) and sExpr[off + 1].isspace():
3330 off += 1;
3331 if off >= len(sExpr):
3332 break;
3333 if sExpr.startswith('||'):
3334 off += 2;
3335 else:
3336 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3337
3338 return False;
3339
3340 @staticmethod
3341 def matchArch(sDefine, sArch):
3342 """ Compares sDefine (RT_ARCH_XXXX) and sArch (x86, amd64, arm64, ++). """
3343 return SimpleParser.PreprocessorConditional.kdBuildArchToIprt[sArch] == sDefine;
3344
3345 @staticmethod
3346 def matchDefined(sExpr, sArch):
3347 """ Check the result of an ifdef/ifndef expression, given sArch. """
3348 iDefine = SimpleParser.PreprocessorConditional.kdKnownDefines.get(sExpr, 0);
3349 if iDefine == -2:
3350 raise Exception('Unsupported define for MC block filtering: %s' % (sExpr,));
3351 return iDefine == 1 or (iDefine == -1 and SimpleParser.PreprocessorConditional.matchArch(sExpr, sArch));
3352
3353 def isArchIncludedInPrimaryBlock(self, sArch):
3354 """ Checks if sArch is included in the (primary) 'if' block. """
3355 if self.sType == 'ifdef':
3356 return self.matchDefined(self.sExpr, sArch);
3357 if self.sType == 'ifndef':
3358 return not self.matchDefined(self.sExpr, sArch);
3359 return self.isArchIncludedInExpr(self.sExpr, sArch);
3360
3361 @staticmethod
3362 def isInBlockForArch(aoCppCondStack, sArch, iLine):
3363 """ Checks if sArch is included in the current conditional block. """
3364 _ = iLine;
3365 #print('debug: isInBlockForArch(%s,%s); line %s' % (len(aoCppCondStack), sArch, iLine), file = sys.stderr);
3366 for oCond in aoCppCondStack:
3367 if oCond.isArchIncludedInPrimaryBlock(sArch):
3368 if oCond.aoElif or oCond.fInElse:
3369 #print('debug: isInBlockForArch -> False #1', file = sys.stderr);
3370 return False;
3371 #print('debug: isInBlockForArch(%s,%s): in IF-block' % (len(aoCppCondStack), sArch), file = sys.stderr);
3372 else:
3373 fFine = False;
3374 for oElifCond in oCond.aoElif:
3375 if oElifCond.isArchIncludedInPrimaryBlock(sArch):
3376 if oElifCond is not oCond.aoElif[-1] or oCond.fInElse:
3377 #print('debug: isInBlockForArch -> False #3', file = sys.stderr);
3378 return False;
3379 fFine = True;
3380 if not fFine and not oCond.fInElse:
3381 #print('debug: isInBlockForArch -> False #4', file = sys.stderr);
3382 return False;
3383 #print('debug: isInBlockForArch -> True', file = sys.stderr);
3384 return True;
3385
3386 def __init__(self, sSrcFile, asLines, sDefaultMap, sHostArch, oInheritMacrosFrom = None):
3387 self.sSrcFile = sSrcFile;
3388 self.asLines = asLines;
3389 self.iLine = 0;
3390 self.iState = self.kiCode;
3391 self.sComment = '';
3392 self.iCommentLine = 0;
3393 self.aoCurInstrs = [] # type: List[Instruction]
3394 self.oCurFunction = None # type: DecoderFunction
3395 self.iMcBlockInFunc = 0;
3396 self.oCurMcBlock = None # type: McBlock
3397 self.dMacros = {} # type: Dict[str, SimpleParser.Macro]
3398 self.oReMacros = None # type: re ##< Regular expression matching invocations of anything in self.dMacros.
3399 if oInheritMacrosFrom:
3400 self.dMacros = dict(oInheritMacrosFrom.dMacros);
3401 self.oReMacros = oInheritMacrosFrom.oReMacros;
3402 self.aoCppCondStack = [] # type: List[PreprocessorConditional] ##< Preprocessor conditional stack.
3403 self.sHostArch = sHostArch;
3404
3405 assert sDefaultMap in g_dInstructionMaps;
3406 self.oDefaultMap = g_dInstructionMaps[sDefaultMap];
3407
3408 self.cTotalInstr = 0;
3409 self.cTotalStubs = 0;
3410 self.cTotalTagged = 0;
3411 self.cTotalMcBlocks = 0;
3412
3413 self.oReMacroName = re.compile('^[A-Za-z_][A-Za-z0-9_]*$');
3414 self.oReMnemonic = re.compile('^[A-Za-z_][A-Za-z0-9_]*$');
3415 self.oReStatsName = re.compile('^[A-Za-z_][A-Za-z0-9_]*$');
3416 self.oReFunctionName= re.compile('^iemOp_[A-Za-z_][A-Za-z0-9_]*$');
3417 self.oReGroupName = re.compile('^og_[a-z0-9]+(|_[a-z0-9]+|_[a-z0-9]+_[a-z0-9]+)$');
3418 self.oReDisEnum = re.compile('^OP_[A-Z0-9_]+$');
3419 self.oReFunTable = re.compile('^(IEM_STATIC|static) +const +PFNIEMOP +g_apfn[A-Za-z0-9_]+ *\[ *\d* *\] *= *$');
3420 self.oReComment = re.compile('//.*?$|/\*.*?\*/'); ## Full comments.
3421 self.oReHashDefine2 = re.compile('(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)\(([^)]*)\)\s*(.*)\Z'); ##< With arguments.
3422 self.oReHashDefine3 = re.compile('(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)[^(]\s*(.*)\Z'); ##< Simple, no arguments.
3423 self.oReMcBeginEnd = re.compile(r'\bIEM_MC_(BEGIN|END|DEFER_TO_CIMPL_[1-5]_RET)\s*\('); ##> Not DEFER_TO_CIMPL_0_RET!
3424 self.fDebug = True;
3425 self.fDebugMc = False;
3426 self.fDebugPreproc = False;
3427
3428 self.dTagHandlers = {
3429 '@opbrief': self.parseTagOpBrief,
3430 '@opdesc': self.parseTagOpDesc,
3431 '@opmnemonic': self.parseTagOpMnemonic,
3432 '@op1': self.parseTagOpOperandN,
3433 '@op2': self.parseTagOpOperandN,
3434 '@op3': self.parseTagOpOperandN,
3435 '@op4': self.parseTagOpOperandN,
3436 '@oppfx': self.parseTagOpPfx,
3437 '@opmaps': self.parseTagOpMaps,
3438 '@opcode': self.parseTagOpcode,
3439 '@opcodesub': self.parseTagOpcodeSub,
3440 '@openc': self.parseTagOpEnc,
3441 '@opfltest': self.parseTagOpEFlags,
3442 '@opflmodify': self.parseTagOpEFlags,
3443 '@opflundef': self.parseTagOpEFlags,
3444 '@opflset': self.parseTagOpEFlags,
3445 '@opflclear': self.parseTagOpEFlags,
3446 '@ophints': self.parseTagOpHints,
3447 '@opdisenum': self.parseTagOpDisEnum,
3448 '@opmincpu': self.parseTagOpMinCpu,
3449 '@opcpuid': self.parseTagOpCpuId,
3450 '@opgroup': self.parseTagOpGroup,
3451 '@opunused': self.parseTagOpUnusedInvalid,
3452 '@opinvalid': self.parseTagOpUnusedInvalid,
3453 '@opinvlstyle': self.parseTagOpUnusedInvalid,
3454 '@optest': self.parseTagOpTest,
3455 '@optestign': self.parseTagOpTestIgnore,
3456 '@optestignore': self.parseTagOpTestIgnore,
3457 '@opcopytests': self.parseTagOpCopyTests,
3458 '@oponly': self.parseTagOpOnlyTest,
3459 '@oponlytest': self.parseTagOpOnlyTest,
3460 '@opxcpttype': self.parseTagOpXcptType,
3461 '@opstats': self.parseTagOpStats,
3462 '@opfunction': self.parseTagOpFunction,
3463 '@opdone': self.parseTagOpDone,
3464 };
3465 for i in range(48):
3466 self.dTagHandlers['@optest%u' % (i,)] = self.parseTagOpTestNum;
3467 self.dTagHandlers['@optest[%u]' % (i,)] = self.parseTagOpTestNum;
3468
3469 self.asErrors = [];
3470
3471 def raiseError(self, sMessage):
3472 """
3473 Raise error prefixed with the source and line number.
3474 """
3475 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iLine, sMessage,));
3476
3477 def raiseCommentError(self, iLineInComment, sMessage):
3478 """
3479 Similar to raiseError, but the line number is iLineInComment + self.iCommentLine.
3480 """
3481 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3482
3483 def error(self, sMessage):
3484 """
3485 Adds an error.
3486 returns False;
3487 """
3488 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iLine, sMessage,));
3489 return False;
3490
3491 def errorOnLine(self, iLine, sMessage):
3492 """
3493 Adds an error.
3494 returns False;
3495 """
3496 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, iLine, sMessage,));
3497 return False;
3498
3499 def errorComment(self, iLineInComment, sMessage):
3500 """
3501 Adds a comment error.
3502 returns False;
3503 """
3504 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3505 return False;
3506
3507 def printErrors(self):
3508 """
3509 Print the errors to stderr.
3510 Returns number of errors.
3511 """
3512 if self.asErrors:
3513 sys.stderr.write(u''.join(self.asErrors));
3514 return len(self.asErrors);
3515
3516 def debug(self, sMessage):
3517 """
3518 For debugging.
3519 """
3520 if self.fDebug:
3521 print('debug: %s' % (sMessage,), file = sys.stderr);
3522
3523 def stripComments(self, sLine):
3524 """
3525 Returns sLine with comments stripped.
3526
3527 Complains if traces of incomplete multi-line comments are encountered.
3528 """
3529 sLine = self.oReComment.sub(" ", sLine);
3530 if sLine.find('/*') >= 0 or sLine.find('*/') >= 0:
3531 self.error('Unexpected multi-line comment will not be handled correctly. Please simplify.');
3532 return sLine;
3533
3534 def parseFunctionTable(self, sLine):
3535 """
3536 Parses a PFNIEMOP table, updating/checking the @oppfx value.
3537
3538 Note! Updates iLine as it consumes the whole table.
3539 """
3540
3541 #
3542 # Extract the table name.
3543 #
3544 sName = re.search(' *([a-zA-Z_0-9]+) *\[', sLine).group(1);
3545 oMap = g_dInstructionMapsByIemName.get(sName);
3546 if not oMap:
3547 self.debug('No map for PFNIEMOP table: %s' % (sName,));
3548 oMap = self.oDefaultMap; # This is wrong wrong wrong.
3549
3550 #
3551 # All but the g_apfnOneByteMap & g_apfnEscF1_E0toFF tables uses four
3552 # entries per byte:
3553 # no prefix, 066h prefix, f3h prefix, f2h prefix
3554 # Those tables has 256 & 32 entries respectively.
3555 #
3556 cEntriesPerByte = 4;
3557 cValidTableLength = 1024;
3558 asPrefixes = ('none', '0x66', '0xf3', '0xf2');
3559
3560 oEntriesMatch = re.search('\[ *(256|32) *\]', sLine);
3561 if oEntriesMatch:
3562 cEntriesPerByte = 1;
3563 cValidTableLength = int(oEntriesMatch.group(1));
3564 asPrefixes = (None,);
3565
3566 #
3567 # The next line should be '{' and nothing else.
3568 #
3569 if self.iLine >= len(self.asLines) or not re.match('^ *{ *$', self.asLines[self.iLine]):
3570 return self.errorOnLine(self.iLine + 1, 'Expected lone "{" on line following PFNIEMOP table %s start' % (sName, ));
3571 self.iLine += 1;
3572
3573 #
3574 # Parse till we find the end of the table.
3575 #
3576 iEntry = 0;
3577 while self.iLine < len(self.asLines):
3578 # Get the next line and strip comments and spaces (assumes no
3579 # multi-line comments).
3580 sLine = self.asLines[self.iLine];
3581 self.iLine += 1;
3582 sLine = self.stripComments(sLine).strip();
3583
3584 # Split the line up into entries, expanding IEMOP_X4 usage.
3585 asEntries = sLine.split(',');
3586 for i in range(len(asEntries) - 1, -1, -1):
3587 sEntry = asEntries[i].strip();
3588 if sEntry.startswith('IEMOP_X4(') and sEntry[-1] == ')':
3589 sEntry = (sEntry[len('IEMOP_X4('):-1]).strip();
3590 asEntries.insert(i + 1, sEntry);
3591 asEntries.insert(i + 1, sEntry);
3592 asEntries.insert(i + 1, sEntry);
3593 if sEntry:
3594 asEntries[i] = sEntry;
3595 else:
3596 del asEntries[i];
3597
3598 # Process the entries.
3599 for sEntry in asEntries:
3600 if sEntry in ('};', '}'):
3601 if iEntry != cValidTableLength:
3602 return self.error('Wrong table length for %s: %#x, expected %#x' % (sName, iEntry, cValidTableLength, ));
3603 return True;
3604 if sEntry.startswith('iemOp_Invalid'):
3605 pass; # skip
3606 else:
3607 # Look up matching instruction by function.
3608 sPrefix = asPrefixes[iEntry % cEntriesPerByte];
3609 sOpcode = '%#04x' % (iEntry // cEntriesPerByte);
3610 aoInstr = g_dAllInstructionsByFunction.get(sEntry);
3611 if aoInstr:
3612 if not isinstance(aoInstr, list):
3613 aoInstr = [aoInstr,];
3614 oInstr = None;
3615 for oCurInstr in aoInstr:
3616 if oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix == sPrefix:
3617 pass;
3618 elif oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix is None:
3619 oCurInstr.sPrefix = sPrefix;
3620 elif oCurInstr.sOpcode is None and oCurInstr.sPrefix is None:
3621 oCurInstr.sOpcode = sOpcode;
3622 oCurInstr.sPrefix = sPrefix;
3623 else:
3624 continue;
3625 oInstr = oCurInstr;
3626 break;
3627 if not oInstr:
3628 oInstr = aoInstr[0].copy(oMap = oMap, sOpcode = sOpcode, sPrefix = sPrefix);
3629 aoInstr.append(oInstr);
3630 g_dAllInstructionsByFunction[sEntry] = aoInstr;
3631 g_aoAllInstructions.append(oInstr);
3632 oMap.aoInstructions.append(oInstr);
3633 else:
3634 self.debug('Function "%s", entry %#04x / byte %#04x in %s, is not associated with an instruction.'
3635 % (sEntry, iEntry, iEntry // cEntriesPerByte, sName,));
3636 iEntry += 1;
3637
3638 return self.error('Unexpected end of file in PFNIEMOP table');
3639
3640 def addInstruction(self, iLine = None):
3641 """
3642 Adds an instruction.
3643 """
3644 oInstr = Instruction(self.sSrcFile, self.iLine if iLine is None else iLine);
3645 g_aoAllInstructions.append(oInstr);
3646 self.aoCurInstrs.append(oInstr);
3647 return oInstr;
3648
3649 def deriveMnemonicAndOperandsFromStats(self, oInstr, sStats):
3650 """
3651 Derives the mnemonic and operands from a IEM stats base name like string.
3652 """
3653 if oInstr.sMnemonic is None:
3654 asWords = sStats.split('_');
3655 oInstr.sMnemonic = asWords[0].lower();
3656 if len(asWords) > 1 and not oInstr.aoOperands:
3657 for sType in asWords[1:]:
3658 if sType in g_kdOpTypes:
3659 oInstr.aoOperands.append(Operand(g_kdOpTypes[sType][1], sType));
3660 else:
3661 #return self.error('unknown operand type: %s (instruction: %s)' % (sType, oInstr))
3662 return False;
3663 return True;
3664
3665 def doneInstructionOne(self, oInstr, iLine):
3666 """
3667 Complete the parsing by processing, validating and expanding raw inputs.
3668 """
3669 assert oInstr.iLineCompleted is None;
3670 oInstr.iLineCompleted = iLine;
3671
3672 #
3673 # Specified instructions.
3674 #
3675 if oInstr.cOpTags > 0:
3676 if oInstr.sStats is None:
3677 pass;
3678
3679 #
3680 # Unspecified legacy stuff. We generally only got a few things to go on here.
3681 # /** Opcode 0x0f 0x00 /0. */
3682 # FNIEMOPRM_DEF(iemOp_Grp6_sldt)
3683 #
3684 else:
3685 #if oInstr.sRawOldOpcodes:
3686 #
3687 #if oInstr.sMnemonic:
3688 pass;
3689
3690 #
3691 # Common defaults.
3692 #
3693
3694 # Guess mnemonic and operands from stats if the former is missing.
3695 if oInstr.sMnemonic is None:
3696 if oInstr.sStats is not None:
3697 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sStats);
3698 elif oInstr.sFunction is not None:
3699 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sFunction.replace('iemOp_', ''));
3700
3701 # Derive the disassembler op enum constant from the mnemonic.
3702 if oInstr.sDisEnum is None and oInstr.sMnemonic is not None:
3703 oInstr.sDisEnum = 'OP_' + oInstr.sMnemonic.upper();
3704
3705 # Derive the IEM statistics base name from mnemonic and operand types.
3706 if oInstr.sStats is None:
3707 if oInstr.sFunction is not None:
3708 oInstr.sStats = oInstr.sFunction.replace('iemOp_', '');
3709 elif oInstr.sMnemonic is not None:
3710 oInstr.sStats = oInstr.sMnemonic;
3711 for oOperand in oInstr.aoOperands:
3712 if oOperand.sType:
3713 oInstr.sStats += '_' + oOperand.sType;
3714
3715 # Derive the IEM function name from mnemonic and operand types.
3716 if oInstr.sFunction is None:
3717 if oInstr.sMnemonic is not None:
3718 oInstr.sFunction = 'iemOp_' + oInstr.sMnemonic;
3719 for oOperand in oInstr.aoOperands:
3720 if oOperand.sType:
3721 oInstr.sFunction += '_' + oOperand.sType;
3722 elif oInstr.sStats:
3723 oInstr.sFunction = 'iemOp_' + oInstr.sStats;
3724
3725 #
3726 # Apply default map and then add the instruction to all it's groups.
3727 #
3728 if not oInstr.aoMaps:
3729 oInstr.aoMaps = [ self.oDefaultMap, ];
3730 for oMap in oInstr.aoMaps:
3731 oMap.aoInstructions.append(oInstr);
3732
3733 #
3734 # Derive encoding from operands and maps.
3735 #
3736 if oInstr.sEncoding is None:
3737 if not oInstr.aoOperands:
3738 if oInstr.fUnused and oInstr.sSubOpcode:
3739 oInstr.sEncoding = 'VEX.ModR/M' if oInstr.onlyInVexMaps() else 'ModR/M';
3740 else:
3741 oInstr.sEncoding = 'VEX.fixed' if oInstr.onlyInVexMaps() else 'fixed';
3742 elif oInstr.aoOperands[0].usesModRM():
3743 if (len(oInstr.aoOperands) >= 2 and oInstr.aoOperands[1].sWhere == 'vvvv') \
3744 or oInstr.onlyInVexMaps():
3745 oInstr.sEncoding = 'VEX.ModR/M';
3746 else:
3747 oInstr.sEncoding = 'ModR/M';
3748
3749 #
3750 # Check the opstat value and add it to the opstat indexed dictionary.
3751 #
3752 if oInstr.sStats:
3753 if oInstr.sStats not in g_dAllInstructionsByStat:
3754 g_dAllInstructionsByStat[oInstr.sStats] = oInstr;
3755 else:
3756 self.error('Duplicate opstat value "%s"\nnew: %s\nold: %s'
3757 % (oInstr.sStats, oInstr, g_dAllInstructionsByStat[oInstr.sStats],));
3758
3759 #
3760 # Add to function indexed dictionary. We allow multiple instructions per function.
3761 #
3762 if oInstr.sFunction:
3763 if oInstr.sFunction not in g_dAllInstructionsByFunction:
3764 g_dAllInstructionsByFunction[oInstr.sFunction] = [oInstr,];
3765 else:
3766 g_dAllInstructionsByFunction[oInstr.sFunction].append(oInstr);
3767
3768 #self.debug('%d..%d: %s; %d @op tags' % (oInstr.iLineCreated, oInstr.iLineCompleted, oInstr.sFunction, oInstr.cOpTags));
3769 return True;
3770
3771 def doneInstructions(self, iLineInComment = None, fEndOfFunction = False):
3772 """
3773 Done with current instruction.
3774 """
3775 for oInstr in self.aoCurInstrs:
3776 self.doneInstructionOne(oInstr, self.iLine if iLineInComment is None else self.iCommentLine + iLineInComment);
3777 if oInstr.fStub:
3778 self.cTotalStubs += 1;
3779
3780 self.cTotalInstr += len(self.aoCurInstrs);
3781
3782 self.sComment = '';
3783 self.aoCurInstrs = [];
3784 if fEndOfFunction:
3785 #self.debug('%s: oCurFunction=None' % (self.iLine, ));
3786 if self.oCurFunction:
3787 self.oCurFunction.complete(self.iLine, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine]);
3788 self.oCurFunction = None;
3789 self.iMcBlockInFunc = 0;
3790 return True;
3791
3792 def setInstrunctionAttrib(self, sAttrib, oValue, fOverwrite = False):
3793 """
3794 Sets the sAttrib of all current instruction to oValue. If fOverwrite
3795 is False, only None values and empty strings are replaced.
3796 """
3797 for oInstr in self.aoCurInstrs:
3798 if fOverwrite is not True:
3799 oOldValue = getattr(oInstr, sAttrib);
3800 if oOldValue is not None:
3801 continue;
3802 setattr(oInstr, sAttrib, oValue);
3803
3804 def setInstrunctionArrayAttrib(self, sAttrib, iEntry, oValue, fOverwrite = False):
3805 """
3806 Sets the iEntry of the array sAttrib of all current instruction to oValue.
3807 If fOverwrite is False, only None values and empty strings are replaced.
3808 """
3809 for oInstr in self.aoCurInstrs:
3810 aoArray = getattr(oInstr, sAttrib);
3811 while len(aoArray) <= iEntry:
3812 aoArray.append(None);
3813 if fOverwrite is True or aoArray[iEntry] is None:
3814 aoArray[iEntry] = oValue;
3815
3816 def parseCommentOldOpcode(self, asLines):
3817 """ Deals with 'Opcode 0xff /4' like comments """
3818 asWords = asLines[0].split();
3819 if len(asWords) >= 2 \
3820 and asWords[0] == 'Opcode' \
3821 and ( asWords[1].startswith('0x')
3822 or asWords[1].startswith('0X')):
3823 asWords = asWords[:1];
3824 for iWord, sWord in enumerate(asWords):
3825 if sWord.startswith('0X'):
3826 sWord = '0x' + sWord[:2];
3827 asWords[iWord] = asWords;
3828 self.setInstrunctionAttrib('sRawOldOpcodes', ' '.join(asWords));
3829
3830 return False;
3831
3832 def ensureInstructionForOpTag(self, iTagLine):
3833 """ Ensure there is an instruction for the op-tag being parsed. """
3834 if not self.aoCurInstrs:
3835 self.addInstruction(self.iCommentLine + iTagLine);
3836 for oInstr in self.aoCurInstrs:
3837 oInstr.cOpTags += 1;
3838 if oInstr.cOpTags == 1:
3839 self.cTotalTagged += 1;
3840 return self.aoCurInstrs[-1];
3841
3842 @staticmethod
3843 def flattenSections(aasSections):
3844 """
3845 Flattens multiline sections into stripped single strings.
3846 Returns list of strings, on section per string.
3847 """
3848 asRet = [];
3849 for asLines in aasSections:
3850 if asLines:
3851 asRet.append(' '.join([sLine.strip() for sLine in asLines]));
3852 return asRet;
3853
3854 @staticmethod
3855 def flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = '\n'):
3856 """
3857 Flattens sections into a simple stripped string with newlines as
3858 section breaks. The final section does not sport a trailing newline.
3859 """
3860 # Typical: One section with a single line.
3861 if len(aasSections) == 1 and len(aasSections[0]) == 1:
3862 return aasSections[0][0].strip();
3863
3864 sRet = '';
3865 for iSection, asLines in enumerate(aasSections):
3866 if asLines:
3867 if iSection > 0:
3868 sRet += sSectionSep;
3869 sRet += sLineSep.join([sLine.strip() for sLine in asLines]);
3870 return sRet;
3871
3872
3873
3874 ## @name Tag parsers
3875 ## @{
3876
3877 def parseTagOpBrief(self, sTag, aasSections, iTagLine, iEndLine):
3878 """
3879 Tag: \@opbrief
3880 Value: Text description, multiple sections, appended.
3881
3882 Brief description. If not given, it's the first sentence from @opdesc.
3883 """
3884 oInstr = self.ensureInstructionForOpTag(iTagLine);
3885
3886 # Flatten and validate the value.
3887 sBrief = self.flattenAllSections(aasSections);
3888 if not sBrief:
3889 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
3890 if sBrief[-1] != '.':
3891 sBrief = sBrief + '.';
3892 if len(sBrief) > 180:
3893 return self.errorComment(iTagLine, '%s: value too long (max 180 chars): %s' % (sTag, sBrief));
3894 offDot = sBrief.find('.');
3895 while 0 <= offDot < len(sBrief) - 1 and sBrief[offDot + 1] != ' ':
3896 offDot = sBrief.find('.', offDot + 1);
3897 if offDot >= 0 and offDot != len(sBrief) - 1:
3898 return self.errorComment(iTagLine, '%s: only one sentence: %s' % (sTag, sBrief));
3899
3900 # Update the instruction.
3901 if oInstr.sBrief is not None:
3902 return self.errorComment(iTagLine, '%s: attempting to overwrite brief "%s" with "%s"'
3903 % (sTag, oInstr.sBrief, sBrief,));
3904 _ = iEndLine;
3905 return True;
3906
3907 def parseTagOpDesc(self, sTag, aasSections, iTagLine, iEndLine):
3908 """
3909 Tag: \@opdesc
3910 Value: Text description, multiple sections, appended.
3911
3912 It is used to describe instructions.
3913 """
3914 oInstr = self.ensureInstructionForOpTag(iTagLine);
3915 if aasSections:
3916 oInstr.asDescSections.extend(self.flattenSections(aasSections));
3917 return True;
3918
3919 _ = sTag; _ = iEndLine;
3920 return True;
3921
3922 def parseTagOpMnemonic(self, sTag, aasSections, iTagLine, iEndLine):
3923 """
3924 Tag: @opmenmonic
3925 Value: mnemonic
3926
3927 The 'mnemonic' value must be a valid C identifier string. Because of
3928 prefixes, groups and whatnot, there times when the mnemonic isn't that
3929 of an actual assembler mnemonic.
3930 """
3931 oInstr = self.ensureInstructionForOpTag(iTagLine);
3932
3933 # Flatten and validate the value.
3934 sMnemonic = self.flattenAllSections(aasSections);
3935 if not self.oReMnemonic.match(sMnemonic):
3936 return self.errorComment(iTagLine, '%s: invalid menmonic name: "%s"' % (sTag, sMnemonic,));
3937 if oInstr.sMnemonic is not None:
3938 return self.errorComment(iTagLine, '%s: attempting to overwrite menmonic "%s" with "%s"'
3939 % (sTag, oInstr.sMnemonic, sMnemonic,));
3940 oInstr.sMnemonic = sMnemonic
3941
3942 _ = iEndLine;
3943 return True;
3944
3945 def parseTagOpOperandN(self, sTag, aasSections, iTagLine, iEndLine):
3946 """
3947 Tags: \@op1, \@op2, \@op3, \@op4
3948 Value: [where:]type
3949
3950 The 'where' value indicates where the operand is found, like the 'reg'
3951 part of the ModR/M encoding. See Instruction.kdOperandLocations for
3952 a list.
3953
3954 The 'type' value indicates the operand type. These follow the types
3955 given in the opcode tables in the CPU reference manuals.
3956 See Instruction.kdOperandTypes for a list.
3957
3958 """
3959 oInstr = self.ensureInstructionForOpTag(iTagLine);
3960 idxOp = int(sTag[-1]) - 1;
3961 assert 0 <= idxOp < 4;
3962
3963 # flatten, split up, and validate the "where:type" value.
3964 sFlattened = self.flattenAllSections(aasSections);
3965 asSplit = sFlattened.split(':');
3966 if len(asSplit) == 1:
3967 sType = asSplit[0];
3968 sWhere = None;
3969 elif len(asSplit) == 2:
3970 (sWhere, sType) = asSplit;
3971 else:
3972 return self.errorComment(iTagLine, 'expected %s value on format "[<where>:]<type>" not "%s"' % (sTag, sFlattened,));
3973
3974 if sType not in g_kdOpTypes:
3975 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
3976 % (sTag, sType, ', '.join(g_kdOpTypes.keys()),));
3977 if sWhere is None:
3978 sWhere = g_kdOpTypes[sType][1];
3979 elif sWhere not in g_kdOpLocations:
3980 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
3981 % (sTag, sWhere, ', '.join(g_kdOpLocations.keys()),));
3982
3983 # Insert the operand, refusing to overwrite an existing one.
3984 while idxOp >= len(oInstr.aoOperands):
3985 oInstr.aoOperands.append(None);
3986 if oInstr.aoOperands[idxOp] is not None:
3987 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s:%s" with "%s:%s"'
3988 % ( sTag, oInstr.aoOperands[idxOp].sWhere, oInstr.aoOperands[idxOp].sType,
3989 sWhere, sType,));
3990 oInstr.aoOperands[idxOp] = Operand(sWhere, sType);
3991
3992 _ = iEndLine;
3993 return True;
3994
3995 def parseTagOpMaps(self, sTag, aasSections, iTagLine, iEndLine):
3996 """
3997 Tag: \@opmaps
3998 Value: map[,map2]
3999
4000 Indicates which maps the instruction is in. There is a default map
4001 associated with each input file.
4002 """
4003 oInstr = self.ensureInstructionForOpTag(iTagLine);
4004
4005 # Flatten, split up and validate the value.
4006 sFlattened = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',');
4007 asMaps = sFlattened.split(',');
4008 if not asMaps:
4009 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
4010 for sMap in asMaps:
4011 if sMap not in g_dInstructionMaps:
4012 return self.errorComment(iTagLine, '%s: invalid map value: %s (valid values: %s)'
4013 % (sTag, sMap, ', '.join(g_dInstructionMaps.keys()),));
4014
4015 # Add the maps to the current list. Throw errors on duplicates.
4016 for oMap in oInstr.aoMaps:
4017 if oMap.sName in asMaps:
4018 return self.errorComment(iTagLine, '%s: duplicate map assignment: %s' % (sTag, oMap.sName));
4019
4020 for sMap in asMaps:
4021 oMap = g_dInstructionMaps[sMap];
4022 if oMap not in oInstr.aoMaps:
4023 oInstr.aoMaps.append(oMap);
4024 else:
4025 self.errorComment(iTagLine, '%s: duplicate map assignment (input): %s' % (sTag, sMap));
4026
4027 _ = iEndLine;
4028 return True;
4029
4030 def parseTagOpPfx(self, sTag, aasSections, iTagLine, iEndLine):
4031 """
4032 Tag: \@oppfx
4033 Value: n/a|none|0x66|0xf3|0xf2
4034
4035 Required prefix for the instruction. (In a (E)VEX context this is the
4036 value of the 'pp' field rather than an actual prefix.)
4037 """
4038 oInstr = self.ensureInstructionForOpTag(iTagLine);
4039
4040 # Flatten and validate the value.
4041 sFlattened = self.flattenAllSections(aasSections);
4042 asPrefixes = sFlattened.split();
4043 if len(asPrefixes) > 1:
4044 return self.errorComment(iTagLine, '%s: max one prefix: %s' % (sTag, asPrefixes,));
4045
4046 sPrefix = asPrefixes[0].lower();
4047 if sPrefix == 'none':
4048 sPrefix = 'none';
4049 elif sPrefix == 'n/a':
4050 sPrefix = None;
4051 else:
4052 if len(sPrefix) == 2:
4053 sPrefix = '0x' + sPrefix;
4054 if not _isValidOpcodeByte(sPrefix):
4055 return self.errorComment(iTagLine, '%s: invalid prefix: %s' % (sTag, sPrefix,));
4056
4057 if sPrefix is not None and sPrefix not in g_kdPrefixes:
4058 return self.errorComment(iTagLine, '%s: invalid prefix: %s (valid %s)' % (sTag, sPrefix, g_kdPrefixes,));
4059
4060 # Set it.
4061 if oInstr.sPrefix is not None:
4062 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sPrefix, sPrefix,));
4063 oInstr.sPrefix = sPrefix;
4064
4065 _ = iEndLine;
4066 return True;
4067
4068 def parseTagOpcode(self, sTag, aasSections, iTagLine, iEndLine):
4069 """
4070 Tag: \@opcode
4071 Value: 0x?? | /reg (TODO: | mr/reg | 11 /reg | !11 /reg | 11 mr/reg | !11 mr/reg)
4072
4073 The opcode byte or sub-byte for the instruction in the context of a map.
4074 """
4075 oInstr = self.ensureInstructionForOpTag(iTagLine);
4076
4077 # Flatten and validate the value.
4078 sOpcode = self.flattenAllSections(aasSections);
4079 if _isValidOpcodeByte(sOpcode):
4080 pass;
4081 elif len(sOpcode) == 2 and sOpcode.startswith('/') and sOpcode[-1] in '012345678':
4082 pass;
4083 elif len(sOpcode) == 4 and sOpcode.startswith('11/') and sOpcode[-1] in '012345678':
4084 pass;
4085 elif len(sOpcode) == 5 and sOpcode.startswith('!11/') and sOpcode[-1] in '012345678':
4086 pass;
4087 else:
4088 return self.errorComment(iTagLine, '%s: invalid opcode: %s' % (sTag, sOpcode,));
4089
4090 # Set it.
4091 if oInstr.sOpcode is not None:
4092 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sOpcode, sOpcode,));
4093 oInstr.sOpcode = sOpcode;
4094
4095 _ = iEndLine;
4096 return True;
4097
4098 def parseTagOpcodeSub(self, sTag, aasSections, iTagLine, iEndLine):
4099 """
4100 Tag: \@opcodesub
4101 Value: none | 11 mr/reg | !11 mr/reg | rex.w=0 | rex.w=1 | vex.l=0 | vex.l=1
4102 | 11 mr/reg vex.l=0 | 11 mr/reg vex.l=1 | !11 mr/reg vex.l=0 | !11 mr/reg vex.l=1
4103
4104 This is a simple way of dealing with encodings where the mod=3 and mod!=3
4105 represents exactly two different instructions. The more proper way would
4106 be to go via maps with two members, but this is faster.
4107 """
4108 oInstr = self.ensureInstructionForOpTag(iTagLine);
4109
4110 # Flatten and validate the value.
4111 sSubOpcode = self.flattenAllSections(aasSections);
4112 if sSubOpcode not in g_kdSubOpcodes:
4113 return self.errorComment(iTagLine, '%s: invalid sub opcode: %s (valid: 11, !11, none)' % (sTag, sSubOpcode,));
4114 sSubOpcode = g_kdSubOpcodes[sSubOpcode][0];
4115
4116 # Set it.
4117 if oInstr.sSubOpcode is not None:
4118 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4119 % ( sTag, oInstr.sSubOpcode, sSubOpcode,));
4120 oInstr.sSubOpcode = sSubOpcode;
4121
4122 _ = iEndLine;
4123 return True;
4124
4125 def parseTagOpEnc(self, sTag, aasSections, iTagLine, iEndLine):
4126 """
4127 Tag: \@openc
4128 Value: ModR/M|fixed|prefix|<map name>
4129
4130 The instruction operand encoding style.
4131 """
4132 oInstr = self.ensureInstructionForOpTag(iTagLine);
4133
4134 # Flatten and validate the value.
4135 sEncoding = self.flattenAllSections(aasSections);
4136 if sEncoding in g_kdEncodings:
4137 pass;
4138 elif sEncoding in g_dInstructionMaps:
4139 pass;
4140 elif not _isValidOpcodeByte(sEncoding):
4141 return self.errorComment(iTagLine, '%s: invalid encoding: %s' % (sTag, sEncoding,));
4142
4143 # Set it.
4144 if oInstr.sEncoding is not None:
4145 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4146 % ( sTag, oInstr.sEncoding, sEncoding,));
4147 oInstr.sEncoding = sEncoding;
4148
4149 _ = iEndLine;
4150 return True;
4151
4152 ## EFlags tag to Instruction attribute name.
4153 kdOpFlagToAttr = {
4154 '@opfltest': 'asFlTest',
4155 '@opflmodify': 'asFlModify',
4156 '@opflundef': 'asFlUndefined',
4157 '@opflset': 'asFlSet',
4158 '@opflclear': 'asFlClear',
4159 };
4160
4161 def parseTagOpEFlags(self, sTag, aasSections, iTagLine, iEndLine):
4162 """
4163 Tags: \@opfltest, \@opflmodify, \@opflundef, \@opflset, \@opflclear
4164 Value: <eflags specifier>
4165
4166 """
4167 oInstr = self.ensureInstructionForOpTag(iTagLine);
4168
4169 # Flatten, split up and validate the values.
4170 asFlags = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',').split(',');
4171 if len(asFlags) == 1 and asFlags[0].lower() == 'none':
4172 asFlags = [];
4173 else:
4174 fRc = True;
4175 for iFlag, sFlag in enumerate(asFlags):
4176 if sFlag not in g_kdEFlagsMnemonics:
4177 if sFlag.strip() in g_kdEFlagsMnemonics:
4178 asFlags[iFlag] = sFlag.strip();
4179 else:
4180 fRc = self.errorComment(iTagLine, '%s: invalid EFLAGS value: %s' % (sTag, sFlag,));
4181 if not fRc:
4182 return False;
4183
4184 # Set them.
4185 asOld = getattr(oInstr, self.kdOpFlagToAttr[sTag]);
4186 if asOld is not None:
4187 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, asOld, asFlags,));
4188 setattr(oInstr, self.kdOpFlagToAttr[sTag], asFlags);
4189
4190 _ = iEndLine;
4191 return True;
4192
4193 def parseTagOpHints(self, sTag, aasSections, iTagLine, iEndLine):
4194 """
4195 Tag: \@ophints
4196 Value: Comma or space separated list of flags and hints.
4197
4198 This covers the disassembler flags table and more.
4199 """
4200 oInstr = self.ensureInstructionForOpTag(iTagLine);
4201
4202 # Flatten as a space separated list, split it up and validate the values.
4203 asHints = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4204 if len(asHints) == 1 and asHints[0].lower() == 'none':
4205 asHints = [];
4206 else:
4207 fRc = True;
4208 for iHint, sHint in enumerate(asHints):
4209 if sHint not in g_kdHints:
4210 if sHint.strip() in g_kdHints:
4211 sHint[iHint] = sHint.strip();
4212 else:
4213 fRc = self.errorComment(iTagLine, '%s: invalid hint value: %s' % (sTag, sHint,));
4214 if not fRc:
4215 return False;
4216
4217 # Append them.
4218 for sHint in asHints:
4219 if sHint not in oInstr.dHints:
4220 oInstr.dHints[sHint] = True; # (dummy value, using dictionary for speed)
4221 else:
4222 self.errorComment(iTagLine, '%s: duplicate hint: %s' % ( sTag, sHint,));
4223
4224 _ = iEndLine;
4225 return True;
4226
4227 def parseTagOpDisEnum(self, sTag, aasSections, iTagLine, iEndLine):
4228 """
4229 Tag: \@opdisenum
4230 Value: OP_XXXX
4231
4232 This is for select a specific (legacy) disassembler enum value for the
4233 instruction.
4234 """
4235 oInstr = self.ensureInstructionForOpTag(iTagLine);
4236
4237 # Flatten and split.
4238 asWords = self.flattenAllSections(aasSections).split();
4239 if len(asWords) != 1:
4240 self.errorComment(iTagLine, '%s: expected exactly one value: %s' % (sTag, asWords,));
4241 if not asWords:
4242 return False;
4243 sDisEnum = asWords[0];
4244 if not self.oReDisEnum.match(sDisEnum):
4245 return self.errorComment(iTagLine, '%s: invalid disassembler OP_XXXX enum: %s (pattern: %s)'
4246 % (sTag, sDisEnum, self.oReDisEnum.pattern));
4247
4248 # Set it.
4249 if oInstr.sDisEnum is not None:
4250 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % (sTag, oInstr.sDisEnum, sDisEnum,));
4251 oInstr.sDisEnum = sDisEnum;
4252
4253 _ = iEndLine;
4254 return True;
4255
4256 def parseTagOpMinCpu(self, sTag, aasSections, iTagLine, iEndLine):
4257 """
4258 Tag: \@opmincpu
4259 Value: <simple CPU name>
4260
4261 Indicates when this instruction was introduced.
4262 """
4263 oInstr = self.ensureInstructionForOpTag(iTagLine);
4264
4265 # Flatten the value, split into words, make sure there's just one, valid it.
4266 asCpus = self.flattenAllSections(aasSections).split();
4267 if len(asCpus) > 1:
4268 self.errorComment(iTagLine, '%s: exactly one CPU name, please: %s' % (sTag, ' '.join(asCpus),));
4269
4270 sMinCpu = asCpus[0];
4271 if sMinCpu in g_kdCpuNames:
4272 oInstr.sMinCpu = sMinCpu;
4273 else:
4274 return self.errorComment(iTagLine, '%s: invalid CPU name: %s (names: %s)'
4275 % (sTag, sMinCpu, ','.join(sorted(g_kdCpuNames)),));
4276
4277 # Set it.
4278 if oInstr.sMinCpu is None:
4279 oInstr.sMinCpu = sMinCpu;
4280 elif oInstr.sMinCpu != sMinCpu:
4281 self.errorComment(iTagLine, '%s: attemting to overwrite "%s" with "%s"' % (sTag, oInstr.sMinCpu, sMinCpu,));
4282
4283 _ = iEndLine;
4284 return True;
4285
4286 def parseTagOpCpuId(self, sTag, aasSections, iTagLine, iEndLine):
4287 """
4288 Tag: \@opcpuid
4289 Value: none | <CPUID flag specifier>
4290
4291 CPUID feature bit which is required for the instruction to be present.
4292 """
4293 oInstr = self.ensureInstructionForOpTag(iTagLine);
4294
4295 # Flatten as a space separated list, split it up and validate the values.
4296 asCpuIds = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4297 if len(asCpuIds) == 1 and asCpuIds[0].lower() == 'none':
4298 asCpuIds = [];
4299 else:
4300 fRc = True;
4301 for iCpuId, sCpuId in enumerate(asCpuIds):
4302 if sCpuId not in g_kdCpuIdFlags:
4303 if sCpuId.strip() in g_kdCpuIdFlags:
4304 sCpuId[iCpuId] = sCpuId.strip();
4305 else:
4306 fRc = self.errorComment(iTagLine, '%s: invalid CPUID value: %s' % (sTag, sCpuId,));
4307 if not fRc:
4308 return False;
4309
4310 # Append them.
4311 for sCpuId in asCpuIds:
4312 if sCpuId not in oInstr.asCpuIds:
4313 oInstr.asCpuIds.append(sCpuId);
4314 else:
4315 self.errorComment(iTagLine, '%s: duplicate CPUID: %s' % ( sTag, sCpuId,));
4316
4317 _ = iEndLine;
4318 return True;
4319
4320 def parseTagOpGroup(self, sTag, aasSections, iTagLine, iEndLine):
4321 """
4322 Tag: \@opgroup
4323 Value: op_grp1[_subgrp2[_subsubgrp3]]
4324
4325 Instruction grouping.
4326 """
4327 oInstr = self.ensureInstructionForOpTag(iTagLine);
4328
4329 # Flatten as a space separated list, split it up and validate the values.
4330 asGroups = self.flattenAllSections(aasSections).split();
4331 if len(asGroups) != 1:
4332 return self.errorComment(iTagLine, '%s: exactly one group, please: %s' % (sTag, asGroups,));
4333 sGroup = asGroups[0];
4334 if not self.oReGroupName.match(sGroup):
4335 return self.errorComment(iTagLine, '%s: invalid group name: %s (valid: %s)'
4336 % (sTag, sGroup, self.oReGroupName.pattern));
4337
4338 # Set it.
4339 if oInstr.sGroup is not None:
4340 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sGroup, sGroup,));
4341 oInstr.sGroup = sGroup;
4342
4343 _ = iEndLine;
4344 return True;
4345
4346 def parseTagOpUnusedInvalid(self, sTag, aasSections, iTagLine, iEndLine):
4347 """
4348 Tag: \@opunused, \@opinvalid, \@opinvlstyle
4349 Value: <invalid opcode behaviour style>
4350
4351 The \@opunused indicates the specification is for a currently unused
4352 instruction encoding.
4353
4354 The \@opinvalid indicates the specification is for an invalid currently
4355 instruction encoding (like UD2).
4356
4357 The \@opinvlstyle just indicates how CPUs decode the instruction when
4358 not supported (\@opcpuid, \@opmincpu) or disabled.
4359 """
4360 oInstr = self.ensureInstructionForOpTag(iTagLine);
4361
4362 # Flatten as a space separated list, split it up and validate the values.
4363 asStyles = self.flattenAllSections(aasSections).split();
4364 if len(asStyles) != 1:
4365 return self.errorComment(iTagLine, '%s: exactly one invalid behviour style, please: %s' % (sTag, asStyles,));
4366 sStyle = asStyles[0];
4367 if sStyle not in g_kdInvalidStyles:
4368 return self.errorComment(iTagLine, '%s: invalid invalid behaviour style: %s (valid: %s)'
4369 % (sTag, sStyle, g_kdInvalidStyles.keys(),));
4370 # Set it.
4371 if oInstr.sInvalidStyle is not None:
4372 return self.errorComment(iTagLine,
4373 '%s: attempting to overwrite "%s" with "%s" (only one @opunused, @opinvalid, @opinvlstyle)'
4374 % ( sTag, oInstr.sInvalidStyle, sStyle,));
4375 oInstr.sInvalidStyle = sStyle;
4376 if sTag == '@opunused':
4377 oInstr.fUnused = True;
4378 elif sTag == '@opinvalid':
4379 oInstr.fInvalid = True;
4380
4381 _ = iEndLine;
4382 return True;
4383
4384 def parseTagOpTest(self, sTag, aasSections, iTagLine, iEndLine): # pylint: disable=too-many-locals
4385 """
4386 Tag: \@optest
4387 Value: [<selectors>[ ]?] <inputs> -> <outputs>
4388 Example: mode==64bit / in1=0xfffffffe:dw in2=1:dw -> out1=0xffffffff:dw outfl=a?,p?
4389
4390 The main idea here is to generate basic instruction tests.
4391
4392 The probably simplest way of handling the diverse input, would be to use
4393 it to produce size optimized byte code for a simple interpreter that
4394 modifies the register input and output states.
4395
4396 An alternative to the interpreter would be creating multiple tables,
4397 but that becomes rather complicated wrt what goes where and then to use
4398 them in an efficient manner.
4399 """
4400 oInstr = self.ensureInstructionForOpTag(iTagLine);
4401
4402 #
4403 # Do it section by section.
4404 #
4405 for asSectionLines in aasSections:
4406 #
4407 # Sort the input into outputs, inputs and selector conditions.
4408 #
4409 sFlatSection = self.flattenAllSections([asSectionLines,]);
4410 if not sFlatSection:
4411 self.errorComment(iTagLine, '%s: missing value (dbg: aasSections=%s)' % ( sTag, aasSections));
4412 continue;
4413 oTest = InstructionTest(oInstr);
4414
4415 asSelectors = [];
4416 asInputs = [];
4417 asOutputs = [];
4418 asCur = asOutputs;
4419 fRc = True;
4420 asWords = sFlatSection.split();
4421 for iWord in range(len(asWords) - 1, -1, -1):
4422 sWord = asWords[iWord];
4423 # Check for array switchers.
4424 if sWord == '->':
4425 if asCur != asOutputs:
4426 fRc = self.errorComment(iTagLine, '%s: "->" shall only occure once: %s' % (sTag, sFlatSection,));
4427 break;
4428 asCur = asInputs;
4429 elif sWord == '/':
4430 if asCur != asInputs:
4431 fRc = self.errorComment(iTagLine, '%s: "/" shall only occure once: %s' % (sTag, sFlatSection,));
4432 break;
4433 asCur = asSelectors;
4434 else:
4435 asCur.insert(0, sWord);
4436
4437 #
4438 # Validate and add selectors.
4439 #
4440 for sCond in asSelectors:
4441 sCondExp = TestSelector.kdPredicates.get(sCond, sCond);
4442 oSelector = None;
4443 for sOp in TestSelector.kasCompareOps:
4444 off = sCondExp.find(sOp);
4445 if off >= 0:
4446 sVariable = sCondExp[:off];
4447 sValue = sCondExp[off + len(sOp):];
4448 if sVariable in TestSelector.kdVariables:
4449 if sValue in TestSelector.kdVariables[sVariable]:
4450 oSelector = TestSelector(sVariable, sOp, sValue);
4451 else:
4452 self.errorComment(iTagLine, '%s: invalid condition value "%s" in "%s" (valid: %s)'
4453 % ( sTag, sValue, sCond,
4454 TestSelector.kdVariables[sVariable].keys(),));
4455 else:
4456 self.errorComment(iTagLine, '%s: invalid condition variable "%s" in "%s" (valid: %s)'
4457 % ( sTag, sVariable, sCond, TestSelector.kdVariables.keys(),));
4458 break;
4459 if oSelector is not None:
4460 for oExisting in oTest.aoSelectors:
4461 if oExisting.sVariable == oSelector.sVariable:
4462 self.errorComment(iTagLine, '%s: already have a selector for variable "%s" (existing: %s, new: %s)'
4463 % ( sTag, oSelector.sVariable, oExisting, oSelector,));
4464 oTest.aoSelectors.append(oSelector);
4465 else:
4466 fRc = self.errorComment(iTagLine, '%s: failed to parse selector: %s' % ( sTag, sCond,));
4467
4468 #
4469 # Validate outputs and inputs, adding them to the test as we go along.
4470 #
4471 for asItems, sDesc, aoDst in [ (asInputs, 'input', oTest.aoInputs), (asOutputs, 'output', oTest.aoOutputs)]:
4472 asValidFieldKinds = [ 'both', sDesc, ];
4473 for sItem in asItems:
4474 oItem = None;
4475 for sOp in TestInOut.kasOperators:
4476 off = sItem.find(sOp);
4477 if off < 0:
4478 continue;
4479 sField = sItem[:off];
4480 sValueType = sItem[off + len(sOp):];
4481 if sField in TestInOut.kdFields \
4482 and TestInOut.kdFields[sField][1] in asValidFieldKinds:
4483 asSplit = sValueType.split(':', 1);
4484 sValue = asSplit[0];
4485 sType = asSplit[1] if len(asSplit) > 1 else TestInOut.kdFields[sField][0];
4486 if sType in TestInOut.kdTypes:
4487 oValid = TestInOut.kdTypes[sType].validate(sValue);
4488 if oValid is True:
4489 if not TestInOut.kdTypes[sType].isAndOrPair(sValue) or sOp == '&|=':
4490 oItem = TestInOut(sField, sOp, sValue, sType);
4491 else:
4492 self.errorComment(iTagLine, '%s: and-or %s value "%s" can only be used with "&|="'
4493 % ( sTag, sDesc, sItem, ));
4494 else:
4495 self.errorComment(iTagLine, '%s: invalid %s value "%s" in "%s" (type: %s): %s'
4496 % ( sTag, sDesc, sValue, sItem, sType, oValid, ));
4497 else:
4498 self.errorComment(iTagLine, '%s: invalid %s type "%s" in "%s" (valid types: %s)'
4499 % ( sTag, sDesc, sType, sItem, TestInOut.kdTypes.keys(),));
4500 else:
4501 self.errorComment(iTagLine, '%s: invalid %s field "%s" in "%s"\nvalid fields: %s'
4502 % ( sTag, sDesc, sField, sItem,
4503 ', '.join([sKey for sKey, asVal in TestInOut.kdFields.items()
4504 if asVal[1] in asValidFieldKinds]),));
4505 break;
4506 if oItem is not None:
4507 for oExisting in aoDst:
4508 if oExisting.sField == oItem.sField and oExisting.sOp == oItem.sOp:
4509 self.errorComment(iTagLine,
4510 '%s: already have a "%s" assignment for field "%s" (existing: %s, new: %s)'
4511 % ( sTag, oItem.sOp, oItem.sField, oExisting, oItem,));
4512 aoDst.append(oItem);
4513 else:
4514 fRc = self.errorComment(iTagLine, '%s: failed to parse assignment: %s' % ( sTag, sItem,));
4515
4516 #
4517 # .
4518 #
4519 if fRc:
4520 oInstr.aoTests.append(oTest);
4521 else:
4522 self.errorComment(iTagLine, '%s: failed to parse test: %s' % (sTag, ' '.join(asWords),));
4523 self.errorComment(iTagLine, '%s: asSelectors=%s / asInputs=%s -> asOutputs=%s'
4524 % (sTag, asSelectors, asInputs, asOutputs,));
4525
4526 _ = iEndLine;
4527 return True;
4528
4529 def parseTagOpTestNum(self, sTag, aasSections, iTagLine, iEndLine):
4530 """
4531 Numbered \@optest tag. Either \@optest42 or \@optest[42].
4532 """
4533 oInstr = self.ensureInstructionForOpTag(iTagLine);
4534
4535 iTest = 0;
4536 if sTag[-1] == ']':
4537 iTest = int(sTag[8:-1]);
4538 else:
4539 iTest = int(sTag[7:]);
4540
4541 if iTest != len(oInstr.aoTests):
4542 self.errorComment(iTagLine, '%s: incorrect test number: %u, actual %u' % (sTag, iTest, len(oInstr.aoTests),));
4543 return self.parseTagOpTest(sTag, aasSections, iTagLine, iEndLine);
4544
4545 def parseTagOpTestIgnore(self, sTag, aasSections, iTagLine, iEndLine):
4546 """
4547 Tag: \@optestign | \@optestignore
4548 Value: <value is ignored>
4549
4550 This is a simple trick to ignore a test while debugging another.
4551
4552 See also \@oponlytest.
4553 """
4554 _ = sTag; _ = aasSections; _ = iTagLine; _ = iEndLine;
4555 return True;
4556
4557 def parseTagOpCopyTests(self, sTag, aasSections, iTagLine, iEndLine):
4558 """
4559 Tag: \@opcopytests
4560 Value: <opstat | function> [..]
4561 Example: \@opcopytests add_Eb_Gb
4562
4563 Trick to avoid duplicating tests for different encodings of the same
4564 operation.
4565 """
4566 oInstr = self.ensureInstructionForOpTag(iTagLine);
4567
4568 # Flatten, validate and append the copy job to the instruction. We execute
4569 # them after parsing all the input so we can handle forward references.
4570 asToCopy = self.flattenAllSections(aasSections).split();
4571 if not asToCopy:
4572 return self.errorComment(iTagLine, '%s: requires at least on reference value' % (sTag,));
4573 for sToCopy in asToCopy:
4574 if sToCopy not in oInstr.asCopyTests:
4575 if self.oReStatsName.match(sToCopy) or self.oReFunctionName.match(sToCopy):
4576 oInstr.asCopyTests.append(sToCopy);
4577 else:
4578 self.errorComment(iTagLine, '%s: invalid instruction reference (opstat or function) "%s" (valid: %s or %s)'
4579 % (sTag, sToCopy, self.oReStatsName.pattern, self.oReFunctionName.pattern));
4580 else:
4581 self.errorComment(iTagLine, '%s: ignoring duplicate "%s"' % (sTag, sToCopy,));
4582
4583 _ = iEndLine;
4584 return True;
4585
4586 def parseTagOpOnlyTest(self, sTag, aasSections, iTagLine, iEndLine):
4587 """
4588 Tag: \@oponlytest | \@oponly
4589 Value: none
4590
4591 Only test instructions with this tag. This is a trick that is handy
4592 for singling out one or two new instructions or tests.
4593
4594 See also \@optestignore.
4595 """
4596 oInstr = self.ensureInstructionForOpTag(iTagLine);
4597
4598 # Validate and add instruction to only test dictionary.
4599 sValue = self.flattenAllSections(aasSections).strip();
4600 if sValue:
4601 return self.errorComment(iTagLine, '%s: does not take any value: %s' % (sTag, sValue));
4602
4603 if oInstr not in g_aoOnlyTestInstructions:
4604 g_aoOnlyTestInstructions.append(oInstr);
4605
4606 _ = iEndLine;
4607 return True;
4608
4609 def parseTagOpXcptType(self, sTag, aasSections, iTagLine, iEndLine):
4610 """
4611 Tag: \@opxcpttype
4612 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]
4613
4614 Sets the SSE or AVX exception type (see SDMv2 2.4, 2.7).
4615 """
4616 oInstr = self.ensureInstructionForOpTag(iTagLine);
4617
4618 # Flatten as a space separated list, split it up and validate the values.
4619 asTypes = self.flattenAllSections(aasSections).split();
4620 if len(asTypes) != 1:
4621 return self.errorComment(iTagLine, '%s: exactly one invalid exception type, please: %s' % (sTag, asTypes,));
4622 sType = asTypes[0];
4623 if sType not in g_kdXcptTypes:
4624 return self.errorComment(iTagLine, '%s: invalid invalid exception type: %s (valid: %s)'
4625 % (sTag, sType, sorted(g_kdXcptTypes.keys()),));
4626 # Set it.
4627 if oInstr.sXcptType is not None:
4628 return self.errorComment(iTagLine,
4629 '%s: attempting to overwrite "%s" with "%s" (only one @opxcpttype)'
4630 % ( sTag, oInstr.sXcptType, sType,));
4631 oInstr.sXcptType = sType;
4632
4633 _ = iEndLine;
4634 return True;
4635
4636 def parseTagOpFunction(self, sTag, aasSections, iTagLine, iEndLine):
4637 """
4638 Tag: \@opfunction
4639 Value: <VMM function name>
4640
4641 This is for explicitly setting the IEM function name. Normally we pick
4642 this up from the FNIEMOP_XXX macro invocation after the description, or
4643 generate it from the mnemonic and operands.
4644
4645 It it thought it maybe necessary to set it when specifying instructions
4646 which implementation isn't following immediately or aren't implemented yet.
4647 """
4648 oInstr = self.ensureInstructionForOpTag(iTagLine);
4649
4650 # Flatten and validate the value.
4651 sFunction = self.flattenAllSections(aasSections);
4652 if not self.oReFunctionName.match(sFunction):
4653 return self.errorComment(iTagLine, '%s: invalid VMM function name: "%s" (valid: %s)'
4654 % (sTag, sFunction, self.oReFunctionName.pattern));
4655
4656 if oInstr.sFunction is not None:
4657 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM function name "%s" with "%s"'
4658 % (sTag, oInstr.sFunction, sFunction,));
4659 oInstr.sFunction = sFunction;
4660
4661 _ = iEndLine;
4662 return True;
4663
4664 def parseTagOpStats(self, sTag, aasSections, iTagLine, iEndLine):
4665 """
4666 Tag: \@opstats
4667 Value: <VMM statistics base name>
4668
4669 This is for explicitly setting the statistics name. Normally we pick
4670 this up from the IEMOP_MNEMONIC macro invocation, or generate it from
4671 the mnemonic and operands.
4672
4673 It it thought it maybe necessary to set it when specifying instructions
4674 which implementation isn't following immediately or aren't implemented yet.
4675 """
4676 oInstr = self.ensureInstructionForOpTag(iTagLine);
4677
4678 # Flatten and validate the value.
4679 sStats = self.flattenAllSections(aasSections);
4680 if not self.oReStatsName.match(sStats):
4681 return self.errorComment(iTagLine, '%s: invalid VMM statistics name: "%s" (valid: %s)'
4682 % (sTag, sStats, self.oReStatsName.pattern));
4683
4684 if oInstr.sStats is not None:
4685 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM statistics base name "%s" with "%s"'
4686 % (sTag, oInstr.sStats, sStats,));
4687 oInstr.sStats = sStats;
4688
4689 _ = iEndLine;
4690 return True;
4691
4692 def parseTagOpDone(self, sTag, aasSections, iTagLine, iEndLine):
4693 """
4694 Tag: \@opdone
4695 Value: none
4696
4697 Used to explictily flush the instructions that have been specified.
4698 """
4699 sFlattened = self.flattenAllSections(aasSections);
4700 if sFlattened != '':
4701 return self.errorComment(iTagLine, '%s: takes no value, found: "%s"' % (sTag, sFlattened,));
4702 _ = sTag; _ = iEndLine;
4703 return self.doneInstructions();
4704
4705 ## @}
4706
4707
4708 def parseComment(self):
4709 """
4710 Parse the current comment (self.sComment).
4711
4712 If it's a opcode specifiying comment, we reset the macro stuff.
4713 """
4714 #
4715 # Reject if comment doesn't seem to contain anything interesting.
4716 #
4717 if self.sComment.find('Opcode') < 0 \
4718 and self.sComment.find('@') < 0:
4719 return False;
4720
4721 #
4722 # Split the comment into lines, removing leading asterisks and spaces.
4723 # Also remove leading and trailing empty lines.
4724 #
4725 asLines = self.sComment.split('\n');
4726 for iLine, sLine in enumerate(asLines):
4727 asLines[iLine] = sLine.lstrip().lstrip('*').lstrip();
4728
4729 while asLines and not asLines[0]:
4730 self.iCommentLine += 1;
4731 asLines.pop(0);
4732
4733 while asLines and not asLines[-1]:
4734 asLines.pop(len(asLines) - 1);
4735
4736 #
4737 # Check for old style: Opcode 0x0f 0x12
4738 #
4739 if asLines[0].startswith('Opcode '):
4740 self.parseCommentOldOpcode(asLines);
4741
4742 #
4743 # Look for @op* tagged data.
4744 #
4745 cOpTags = 0;
4746 sFlatDefault = None;
4747 sCurTag = '@default';
4748 iCurTagLine = 0;
4749 asCurSection = [];
4750 aasSections = [ asCurSection, ];
4751 for iLine, sLine in enumerate(asLines):
4752 if not sLine.startswith('@'):
4753 if sLine:
4754 asCurSection.append(sLine);
4755 elif asCurSection:
4756 asCurSection = [];
4757 aasSections.append(asCurSection);
4758 else:
4759 #
4760 # Process the previous tag.
4761 #
4762 if not asCurSection and len(aasSections) > 1:
4763 aasSections.pop(-1);
4764 if sCurTag in self.dTagHandlers:
4765 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
4766 cOpTags += 1;
4767 elif sCurTag.startswith('@op'):
4768 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
4769 elif sCurTag == '@default':
4770 sFlatDefault = self.flattenAllSections(aasSections);
4771 elif '@op' + sCurTag[1:] in self.dTagHandlers:
4772 self.errorComment(iCurTagLine, 'Did you mean "@op%s" rather than "%s"?' % (sCurTag[1:], sCurTag));
4773 elif sCurTag in ['@encoding', '@opencoding']:
4774 self.errorComment(iCurTagLine, 'Did you mean "@openc" rather than "%s"?' % (sCurTag,));
4775
4776 #
4777 # New tag.
4778 #
4779 asSplit = sLine.split(None, 1);
4780 sCurTag = asSplit[0].lower();
4781 if len(asSplit) > 1:
4782 asCurSection = [asSplit[1],];
4783 else:
4784 asCurSection = [];
4785 aasSections = [asCurSection, ];
4786 iCurTagLine = iLine;
4787
4788 #
4789 # Process the final tag.
4790 #
4791 if not asCurSection and len(aasSections) > 1:
4792 aasSections.pop(-1);
4793 if sCurTag in self.dTagHandlers:
4794 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
4795 cOpTags += 1;
4796 elif sCurTag.startswith('@op'):
4797 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
4798 elif sCurTag == '@default':
4799 sFlatDefault = self.flattenAllSections(aasSections);
4800
4801 #
4802 # Don't allow default text in blocks containing @op*.
4803 #
4804 if cOpTags > 0 and sFlatDefault:
4805 self.errorComment(0, 'Untagged comment text is not allowed with @op*: %s' % (sFlatDefault,));
4806
4807 return True;
4808
4809 def parseMacroInvocation(self, sInvocation, offStartInvocation = 0):
4810 """
4811 Parses a macro invocation.
4812
4813 Returns three values:
4814 1. A list of macro arguments, where the zero'th is the macro name.
4815 2. The offset following the macro invocation, into sInvocation of
4816 this is on the same line or into the last line if it is on a
4817 different line.
4818 3. Number of additional lines the invocation spans (i.e. zero if
4819 it is all contained within sInvocation).
4820 """
4821 # First the name.
4822 offOpen = sInvocation.find('(', offStartInvocation);
4823 if offOpen <= offStartInvocation:
4824 self.raiseError("macro invocation open parenthesis not found");
4825 sName = sInvocation[offStartInvocation:offOpen].strip();
4826 if not self.oReMacroName.match(sName):
4827 self.raiseError("invalid macro name '%s'" % (sName,));
4828 asRet = [sName, ];
4829
4830 # Arguments.
4831 iLine = self.iLine;
4832 cDepth = 1;
4833 off = offOpen + 1;
4834 offStart = off;
4835 offCurLn = 0;
4836 chQuote = None;
4837 while cDepth > 0:
4838 if off >= len(sInvocation):
4839 if iLine >= len(self.asLines):
4840 self.error('macro invocation beyond end of file');
4841 return (asRet, off - offCurLn, iLine - self.iLine);
4842 offCurLn = off;
4843 sInvocation += self.asLines[iLine];
4844 iLine += 1;
4845 ch = sInvocation[off];
4846
4847 if chQuote:
4848 if ch == '\\' and off + 1 < len(sInvocation):
4849 off += 1;
4850 elif ch == chQuote:
4851 chQuote = None;
4852 elif ch in ('"', '\'',):
4853 chQuote = ch;
4854 elif ch in (',', ')',):
4855 if cDepth == 1:
4856 asRet.append(sInvocation[offStart:off].strip());
4857 offStart = off + 1;
4858 if ch == ')':
4859 cDepth -= 1;
4860 elif ch == '(':
4861 cDepth += 1;
4862 off += 1;
4863
4864 return (asRet, off - offCurLn, iLine - self.iLine);
4865
4866 def findAndParseMacroInvocationEx(self, sCode, sMacro, offStart = 0):
4867 """
4868 Returns (None, len(sCode), 0) if not found, otherwise the
4869 parseMacroInvocation() return value.
4870 """
4871 offHit = sCode.find(sMacro, offStart);
4872 if offHit >= 0 and sCode[offHit + len(sMacro):].strip()[0] == '(':
4873 return self.parseMacroInvocation(sCode, offHit);
4874 return (None, len(sCode), 0);
4875
4876 def findAndParseMacroInvocation(self, sCode, sMacro):
4877 """
4878 Returns None if not found, arguments as per parseMacroInvocation if found.
4879 """
4880 return self.findAndParseMacroInvocationEx(sCode, sMacro)[0];
4881
4882 def findAndParseFirstMacroInvocation(self, sCode, asMacro):
4883 """
4884 Returns same as findAndParseMacroInvocation.
4885 """
4886 for sMacro in asMacro:
4887 asRet = self.findAndParseMacroInvocation(sCode, sMacro);
4888 if asRet is not None:
4889 return asRet;
4890 return None;
4891
4892 def workerIemOpMnemonicEx(self, sMacro, sStats, sAsm, sForm, sUpper, sLower, # pylint: disable=too-many-arguments
4893 sDisHints, sIemHints, asOperands):
4894 """
4895 Processes one of the a IEMOP_MNEMONIC0EX, IEMOP_MNEMONIC1EX, IEMOP_MNEMONIC2EX,
4896 IEMOP_MNEMONIC3EX, and IEMOP_MNEMONIC4EX macros.
4897 """
4898 #
4899 # Some invocation checks.
4900 #
4901 if sUpper != sUpper.upper():
4902 self.error('%s: bad a_Upper parameter: %s' % (sMacro, sUpper,));
4903 if sLower != sLower.lower():
4904 self.error('%s: bad a_Lower parameter: %s' % (sMacro, sLower,));
4905 if sUpper.lower() != sLower:
4906 self.error('%s: a_Upper and a_Lower parameters does not match: %s vs %s' % (sMacro, sUpper, sLower,));
4907 if not self.oReMnemonic.match(sLower):
4908 self.error('%s: invalid a_Lower: %s (valid: %s)' % (sMacro, sLower, self.oReMnemonic.pattern,));
4909
4910 #
4911 # Check if sIemHints tells us to not consider this macro invocation.
4912 #
4913 if sIemHints.find('IEMOPHINT_SKIP_PYTHON') >= 0:
4914 return True;
4915
4916 # Apply to the last instruction only for now.
4917 if not self.aoCurInstrs:
4918 self.addInstruction();
4919 oInstr = self.aoCurInstrs[-1];
4920 if oInstr.iLineMnemonicMacro == -1:
4921 oInstr.iLineMnemonicMacro = self.iLine;
4922 else:
4923 self.error('%s: already saw a IEMOP_MNEMONIC* macro on line %u for this instruction'
4924 % (sMacro, oInstr.iLineMnemonicMacro,));
4925
4926 # Mnemonic
4927 if oInstr.sMnemonic is None:
4928 oInstr.sMnemonic = sLower;
4929 elif oInstr.sMnemonic != sLower:
4930 self.error('%s: current instruction and a_Lower does not match: %s vs %s' % (sMacro, oInstr.sMnemonic, sLower,));
4931
4932 # Process operands.
4933 if len(oInstr.aoOperands) not in [0, len(asOperands)]:
4934 self.error('%s: number of operands given by @opN does not match macro: %s vs %s'
4935 % (sMacro, len(oInstr.aoOperands), len(asOperands),));
4936 for iOperand, sType in enumerate(asOperands):
4937 sWhere = g_kdOpTypes.get(sType, [None, None])[1];
4938 if sWhere is None:
4939 self.error('%s: unknown a_Op%u value: %s' % (sMacro, iOperand + 1, sType));
4940 if iOperand < len(oInstr.aoOperands): # error recovery.
4941 sWhere = oInstr.aoOperands[iOperand].sWhere;
4942 sType = oInstr.aoOperands[iOperand].sType;
4943 else:
4944 sWhere = 'reg';
4945 sType = 'Gb';
4946 if iOperand == len(oInstr.aoOperands):
4947 oInstr.aoOperands.append(Operand(sWhere, sType))
4948 elif oInstr.aoOperands[iOperand].sWhere != sWhere or oInstr.aoOperands[iOperand].sType != sType:
4949 self.error('%s: @op%u and a_Op%u mismatch: %s:%s vs %s:%s'
4950 % (sMacro, iOperand + 1, iOperand + 1, oInstr.aoOperands[iOperand].sWhere,
4951 oInstr.aoOperands[iOperand].sType, sWhere, sType,));
4952
4953 # Encoding.
4954 if sForm not in g_kdIemForms:
4955 self.error('%s: unknown a_Form value: %s' % (sMacro, sForm,));
4956 else:
4957 if oInstr.sEncoding is None:
4958 oInstr.sEncoding = g_kdIemForms[sForm][0];
4959 elif g_kdIemForms[sForm][0] != oInstr.sEncoding:
4960 self.error('%s: current instruction @openc and a_Form does not match: %s vs %s (%s)'
4961 % (sMacro, oInstr.sEncoding, g_kdIemForms[sForm], sForm));
4962
4963 # Check the parameter locations for the encoding.
4964 if g_kdIemForms[sForm][1] is not None:
4965 if len(g_kdIemForms[sForm][1]) > len(oInstr.aoOperands):
4966 self.error('%s: The a_Form=%s has a different operand count: %s (form) vs %s'
4967 % (sMacro, sForm, len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands) ));
4968 else:
4969 for iOperand, sWhere in enumerate(g_kdIemForms[sForm][1]):
4970 if oInstr.aoOperands[iOperand].sWhere != sWhere:
4971 self.error('%s: current instruction @op%u and a_Form location does not match: %s vs %s (%s)'
4972 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sWhere, sWhere, sForm,));
4973 sOpFormMatch = g_kdOpTypes[oInstr.aoOperands[iOperand].sType][4];
4974 if (sOpFormMatch in [ 'REG', 'MEM', ] and sForm.find('_' + sOpFormMatch) < 0) \
4975 or (sOpFormMatch in [ 'FIXED', ] and sForm.find(sOpFormMatch) < 0) \
4976 or (sOpFormMatch == 'RM' and (sForm.find('_MEM') > 0 or sForm.find('_REG') > 0) ) \
4977 or (sOpFormMatch == 'V' and ( not (sForm.find('VEX') > 0 or sForm.find('XOP')) \
4978 or sForm.replace('VEX','').find('V') < 0) ):
4979 self.error('%s: current instruction @op%u and a_Form type does not match: %s/%s vs %s'
4980 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sType, sOpFormMatch, sForm, ));
4981 if len(g_kdIemForms[sForm][1]) < len(oInstr.aoOperands):
4982 for iOperand in range(len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands)):
4983 if oInstr.aoOperands[iOperand].sType != 'FIXED' \
4984 and g_kdOpTypes[oInstr.aoOperands[iOperand].sType][0] != 'IDX_ParseFixedReg':
4985 self.error('%s: Expected FIXED type operand #%u following operands given by a_Form=%s: %s (%s)'
4986 % (sMacro, iOperand, sForm, oInstr.aoOperands[iOperand].sType,
4987 oInstr.aoOperands[iOperand].sWhere));
4988
4989
4990 # Check @opcodesub
4991 if oInstr.sSubOpcode \
4992 and g_kdIemForms[sForm][2] \
4993 and oInstr.sSubOpcode.find(g_kdIemForms[sForm][2]) < 0:
4994 self.error('%s: current instruction @opcodesub and a_Form does not match: %s vs %s (%s)'
4995 % (sMacro, oInstr.sSubOpcode, g_kdIemForms[sForm][2], sForm,));
4996
4997 # Stats.
4998 if not self.oReStatsName.match(sStats):
4999 self.error('%s: invalid a_Stats value: %s' % (sMacro, sStats,));
5000 elif oInstr.sStats is None:
5001 oInstr.sStats = sStats;
5002 elif oInstr.sStats != sStats:
5003 self.error('%s: mismatching @opstats and a_Stats value: %s vs %s'
5004 % (sMacro, oInstr.sStats, sStats,));
5005
5006 # Process the hints (simply merge with @ophints w/o checking anything).
5007 for sHint in sDisHints.split('|'):
5008 sHint = sHint.strip();
5009 if sHint.startswith('DISOPTYPE_'):
5010 sShortHint = sHint[len('DISOPTYPE_'):].lower();
5011 if sShortHint in g_kdHints:
5012 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5013 else:
5014 self.error('%s: unknown a_fDisHints value: %s' % (sMacro, sHint,));
5015 elif sHint != '0':
5016 self.error('%s: expected a_fDisHints value: %s' % (sMacro, sHint,));
5017
5018 for sHint in sIemHints.split('|'):
5019 sHint = sHint.strip();
5020 if sHint.startswith('IEMOPHINT_'):
5021 sShortHint = sHint[len('IEMOPHINT_'):].lower();
5022 if sShortHint in g_kdHints:
5023 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5024 else:
5025 self.error('%s: unknown a_fIemHints value: %s' % (sMacro, sHint,));
5026 elif sHint != '0':
5027 self.error('%s: expected a_fIemHints value: %s' % (sMacro, sHint,));
5028
5029 _ = sAsm;
5030 return True;
5031
5032 def workerIemOpMnemonic(self, sMacro, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands):
5033 """
5034 Processes one of the a IEMOP_MNEMONIC0, IEMOP_MNEMONIC1, IEMOP_MNEMONIC2,
5035 IEMOP_MNEMONIC3, and IEMOP_MNEMONIC4 macros.
5036 """
5037 if not asOperands:
5038 return self.workerIemOpMnemonicEx(sMacro, sLower, sLower, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5039 return self.workerIemOpMnemonicEx(sMacro, sLower + '_' + '_'.join(asOperands), sLower + ' ' + ','.join(asOperands),
5040 sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5041
5042 def workerIemMcBegin(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine):
5043 """
5044 Process a IEM_MC_BEGIN macro invocation.
5045 """
5046 if self.fDebugMc:
5047 self.debug('IEM_MC_BEGIN on %s off %s' % (self.iLine, offBeginStatementInLine,));
5048 #self.debug('%s<eos>' % (sCode,));
5049
5050 # Check preconditions.
5051 if not self.oCurFunction:
5052 self.raiseError('IEM_MC_BEGIN w/o current function (%s)' % (sCode,));
5053 if self.oCurMcBlock:
5054 self.raiseError('IEM_MC_BEGIN before IEM_MC_END. Previous IEM_MC_BEGIN at line %u' % (self.oCurMcBlock.iBeginLine,));
5055
5056 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5057 cchIndent = offBeginStatementInCodeStr;
5058 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5059 if offPrevNewline >= 0:
5060 cchIndent -= offPrevNewline + 1;
5061 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5062
5063 # Start a new block.
5064 # But don't add it to the list unless the context matches the host architecture.
5065 self.oCurMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine,
5066 self.oCurFunction, self.iMcBlockInFunc, cchIndent);
5067 try:
5068 if ( not self.aoCppCondStack
5069 or not self.sHostArch
5070 or self.PreprocessorConditional.isInBlockForArch(self.aoCppCondStack, self.sHostArch, self.iLine)):
5071 g_aoMcBlocks.append(self.oCurMcBlock);
5072 self.cTotalMcBlocks += 1;
5073 except Exception as oXcpt:
5074 self.raiseError(oXcpt.args[0]);
5075
5076 self.iMcBlockInFunc += 1;
5077 return True;
5078
5079 @staticmethod
5080 def extractLinesFromMacroExpansionLine(sRawLine, offBegin, offEnd, sBeginStmt = 'IEM_MC_BEGIN'):
5081 """
5082 Helper used by workerIemMcEnd and workerIemMcDeferToCImplXRet for
5083 extracting a statement block from a string that's the result of macro
5084 expansion and therefore contains multiple "sub-lines" as it were.
5085
5086 Returns list of lines covering offBegin thru offEnd in sRawLine.
5087 """
5088
5089 off = sRawLine.find('\n', offEnd);
5090 if off > 0:
5091 sRawLine = sRawLine[:off + 1];
5092
5093 off = sRawLine.rfind('\n', 0, offBegin) + 1;
5094 sRawLine = sRawLine[off:];
5095 if not sRawLine.strip().startswith(sBeginStmt):
5096 sRawLine = sRawLine[offBegin - off:]
5097
5098 return [sLine + '\n' for sLine in sRawLine.split('\n')];
5099
5100 def workerIemMcEnd(self, offEndStatementInLine):
5101 """
5102 Process a IEM_MC_END macro invocation.
5103 """
5104 if self.fDebugMc:
5105 self.debug('IEM_MC_END on %s off %s' % (self.iLine, offEndStatementInLine,));
5106
5107 # Check preconditions.
5108 if not self.oCurMcBlock:
5109 self.raiseError('IEM_MC_END w/o IEM_MC_BEGIN.');
5110
5111 #
5112 # HACK ALERT! For blocks originating from macro expansion the start and
5113 # end line will be the same, but the line has multiple
5114 # newlines inside it. So, we have to do some extra tricks
5115 # to get the lines out of there. We ASSUME macros aren't
5116 # messy, but keep IEM_MC_BEGIN/END on separate lines.
5117 #
5118 if self.iLine > self.oCurMcBlock.iBeginLine:
5119 asLines = self.asLines[self.oCurMcBlock.iBeginLine - 1 : self.iLine];
5120 if not asLines[0].strip().startswith('IEM_MC_BEGIN'):
5121 self.raiseError('IEM_MC_BEGIN is not the first word on the line');
5122
5123 # Hack alert! Detect mixed tail/head macros a la cmpxchg16b and split up the lines
5124 # so we can deal correctly with IEM_MC_END below and everything else.
5125 for sLine in asLines:
5126 cNewLines = sLine.count('\n');
5127 assert cNewLines > 0;
5128 if cNewLines > 1:
5129 asLines = self.extractLinesFromMacroExpansionLine(''.join(asLines),
5130 self.oCurMcBlock.offBeginLine,
5131 offEndStatementInLine
5132 + sum(len(s) for s in asLines)
5133 - len(asLines[-1]));
5134 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Partial;
5135 break;
5136 else:
5137 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Entire;
5138 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1],
5139 self.oCurMcBlock.offBeginLine, offEndStatementInLine);
5140
5141 #
5142 # Strip anything following the IEM_MC_END(); statement in the final line,
5143 # so that we don't carry on any trailing 'break' after macro expansions
5144 # like for iemOp_movsb_Xb_Yb.
5145 #
5146 while asLines[-1].strip() == '':
5147 asLines.pop();
5148 sFinal = asLines[-1];
5149 offFinalEnd = sFinal.find('IEM_MC_END');
5150 offEndInFinal = offFinalEnd;
5151 if offFinalEnd < 0: self.raiseError('bogus IEM_MC_END: Not in final line: %s' % (sFinal,));
5152 offFinalEnd += len('IEM_MC_END');
5153
5154 while sFinal[offFinalEnd].isspace():
5155 offFinalEnd += 1;
5156 if sFinal[offFinalEnd] != '(': self.raiseError('bogus IEM_MC_END: Expected "(" at %s: %s' % (offFinalEnd, sFinal,));
5157 offFinalEnd += 1;
5158
5159 while sFinal[offFinalEnd].isspace():
5160 offFinalEnd += 1;
5161 if sFinal[offFinalEnd] != ')': self.raiseError('bogus IEM_MC_END: Expected ")" at %s: %s' % (offFinalEnd, sFinal,));
5162 offFinalEnd += 1;
5163
5164 while sFinal[offFinalEnd].isspace():
5165 offFinalEnd += 1;
5166 if sFinal[offFinalEnd] != ';': self.raiseError('bogus IEM_MC_END: Expected ";" at %s: %s' % (offFinalEnd, sFinal,));
5167 offFinalEnd += 1;
5168
5169 asLines[-1] = sFinal[: offFinalEnd];
5170
5171 #
5172 # Complete and discard the current block.
5173 #
5174 self.oCurMcBlock.complete(self.iLine, offEndStatementInLine,
5175 offEndStatementInLine + offFinalEnd - offEndInFinal, asLines);
5176 self.oCurMcBlock = None;
5177 return True;
5178
5179 def workerIemMcDeferToCImplXRet(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine, cParams):
5180 """
5181 Process a IEM_MC_DEFER_TO_CIMPL_[1-5]_RET macro invocation.
5182 """
5183 sStmt = 'IEM_MC_DEFER_TO_CIMPL_%d_RET' % (cParams,);
5184 if self.fDebugMc:
5185 self.debug('%s on %s off %s' % (sStmt, self.iLine, offBeginStatementInLine,));
5186 #self.debug('%s<eos>' % (sCode,));
5187
5188 # Check preconditions.
5189 if not self.oCurFunction:
5190 self.raiseError('%s w/o current function (%s)' % (sStmt, sCode,));
5191 if self.oCurMcBlock:
5192 self.raiseError('%s inside IEM_MC_BEGIN blocki starting at line %u' % (sStmt, self.oCurMcBlock.iBeginLine,));
5193
5194 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5195 cchIndent = offBeginStatementInCodeStr;
5196 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5197 if offPrevNewline >= 0:
5198 cchIndent -= offPrevNewline + 1;
5199 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5200
5201 # Start a new block.
5202 oMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine,
5203 self.oCurFunction, self.iMcBlockInFunc, cchIndent);
5204
5205 # Parse the statment.
5206 asArgs, offAfter, cLines = self.findAndParseMacroInvocationEx(sCode, sStmt, offBeginStatementInCodeStr);
5207 if asArgs is None:
5208 self.raiseError('%s: Closing parenthesis not found!' % (sStmt,));
5209 if len(asArgs) != cParams + 4:
5210 self.raiseError('%s: findAndParseMacroInvocationEx returns %s args, expected %s! (%s)'
5211 % (sStmt, len(asArgs), cParams + 4, asArgs));
5212
5213 oMcBlock.aoStmts = [ McBlock.parseMcDeferToCImpl(oMcBlock, asArgs[0], asArgs[1:]), ];
5214
5215 # These MCs are not typically part of macro expansions, but let's get
5216 # it out of the way immediately if it's the case.
5217 if cLines > 0 or self.asLines[oMcBlock.iBeginLine - 1].count('\n') <= 1:
5218 asLines = self.asLines[self.iLine - 1 : self.iLine - 1 + cLines + 1];
5219 assert offAfter < len(asLines[-1]) and asLines[-1][offAfter] == ';', \
5220 'iBeginLine=%d iLine=%d offAfter=%s line: "%s"' % (oMcBlock.iBeginLine, self.iLine, offAfter, asLines[-1],);
5221 asLines[-1] = asLines[-1][:offAfter + 1];
5222 else:
5223 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1], offBeginStatementInCodeStr,
5224 offAfter, sStmt);
5225 assert asLines[-1].find(';') >= 0;
5226 asLines[-1] = asLines[-1][:asLines[-1].find(';') + 1];
5227
5228 assert asLines[0].find(sStmt) >= 0;
5229 #if not asLines[0].strip().startswith(sStmt):
5230 # self.raiseError('%s is not the first word on the line: %s' % (sStmt, asLines[0].strip()));
5231
5232 # Advance to the line with the closing ')'.
5233 self.iLine += cLines;
5234
5235 # Complete the block.
5236 oMcBlock.complete(self.iLine, 0 if cLines > 0 else offBeginStatementInCodeStr, offAfter + 1, asLines);
5237
5238 g_aoMcBlocks.append(oMcBlock);
5239 self.cTotalMcBlocks += 1;
5240 self.iMcBlockInFunc += 1;
5241
5242 return True;
5243
5244 def workerStartFunction(self, asArgs):
5245 """
5246 Deals with the start of a decoder function.
5247
5248 These are all defined using one of the FNIEMOP*_DEF* and FNIEMOP_*STUB*
5249 macros, so we get a argument list for these where the 0th argument is the
5250 macro name.
5251 """
5252 # Complete any existing function.
5253 if self.oCurFunction:
5254 self.oCurFunction.complete(self.iLine - 1, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine - 1]);
5255
5256 # Create the new function.
5257 self.oCurFunction = DecoderFunction(self.sSrcFile, self.iLine, asArgs[1], asArgs);
5258 return True;
5259
5260 def checkCodeForMacro(self, sCode, offLine):
5261 """
5262 Checks code for relevant macro invocation.
5263 """
5264
5265 #
5266 # Scan macro invocations.
5267 #
5268 if sCode.find('(') > 0:
5269 # Look for instruction decoder function definitions. ASSUME single line.
5270 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5271 [ 'FNIEMOP_DEF',
5272 'FNIEMOPRM_DEF',
5273 'FNIEMOP_STUB',
5274 'FNIEMOP_STUB_1',
5275 'FNIEMOP_UD_STUB',
5276 'FNIEMOP_UD_STUB_1' ]);
5277 if asArgs is not None:
5278 self.workerStartFunction(asArgs);
5279 #self.debug('%s: oCurFunction=%s' % (self.iLine, self.oCurFunction.sName,));
5280
5281 if not self.aoCurInstrs:
5282 self.addInstruction();
5283 for oInstr in self.aoCurInstrs:
5284 if oInstr.iLineFnIemOpMacro == -1:
5285 oInstr.iLineFnIemOpMacro = self.iLine;
5286 else:
5287 self.error('%s: already seen a FNIEMOP_XXX macro for %s' % (asArgs[0], oInstr,) );
5288 self.setInstrunctionAttrib('sFunction', asArgs[1]);
5289 self.setInstrunctionAttrib('fStub', asArgs[0].find('STUB') > 0, fOverwrite = True);
5290 self.setInstrunctionAttrib('fUdStub', asArgs[0].find('UD_STUB') > 0, fOverwrite = True);
5291 if asArgs[0].find('STUB') > 0:
5292 self.doneInstructions(fEndOfFunction = True);
5293 return True;
5294
5295 # Check for worker function definitions, so we can get a context for MC blocks.
5296 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5297 [ 'FNIEMOP_DEF_1',
5298 'FNIEMOP_DEF_2', ]);
5299 if asArgs is not None:
5300 self.workerStartFunction(asArgs);
5301 #self.debug('%s: oCurFunction=%s (%s)' % (self.iLine, self.oCurFunction.sName, asArgs[0]));
5302 return True;
5303
5304 # IEMOP_HLP_DONE_VEX_DECODING_*
5305 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5306 [ 'IEMOP_HLP_DONE_VEX_DECODING',
5307 'IEMOP_HLP_DONE_VEX_DECODING_L0',
5308 'IEMOP_HLP_DONE_VEX_DECODING_NO_VVVV',
5309 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV',
5310 ]);
5311 if asArgs is not None:
5312 sMacro = asArgs[0];
5313 if sMacro in ('IEMOP_HLP_DONE_VEX_DECODING_L0', 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV', ):
5314 for oInstr in self.aoCurInstrs:
5315 if 'vex_l_zero' not in oInstr.dHints:
5316 if oInstr.iLineMnemonicMacro >= 0:
5317 self.errorOnLine(oInstr.iLineMnemonicMacro,
5318 'Missing IEMOPHINT_VEX_L_ZERO! (%s on line %d)' % (sMacro, self.iLine,));
5319 oInstr.dHints['vex_l_zero'] = True;
5320
5321 #
5322 # IEMOP_MNEMONIC*
5323 #
5324 if sCode.find('IEMOP_MNEMONIC') >= 0:
5325 # IEMOP_MNEMONIC(a_Stats, a_szMnemonic) IEMOP_INC_STATS(a_Stats)
5326 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC');
5327 if asArgs is not None:
5328 if len(self.aoCurInstrs) == 1:
5329 oInstr = self.aoCurInstrs[0];
5330 if oInstr.sStats is None:
5331 oInstr.sStats = asArgs[1];
5332 self.deriveMnemonicAndOperandsFromStats(oInstr, asArgs[1]);
5333
5334 # IEMOP_MNEMONIC0EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5335 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0EX');
5336 if asArgs is not None:
5337 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[6],
5338 asArgs[7], []);
5339 # IEMOP_MNEMONIC1EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5340 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1EX');
5341 if asArgs is not None:
5342 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[7],
5343 asArgs[8], [asArgs[6],]);
5344 # IEMOP_MNEMONIC2EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5345 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2EX');
5346 if asArgs is not None:
5347 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[8],
5348 asArgs[9], [asArgs[6], asArgs[7]]);
5349 # IEMOP_MNEMONIC3EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints,
5350 # a_fIemHints)
5351 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3EX');
5352 if asArgs is not None:
5353 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[9],
5354 asArgs[10], [asArgs[6], asArgs[7], asArgs[8],]);
5355 # IEMOP_MNEMONIC4EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints,
5356 # a_fIemHints)
5357 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4EX');
5358 if asArgs is not None:
5359 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[10],
5360 asArgs[11], [asArgs[6], asArgs[7], asArgs[8], asArgs[9],]);
5361
5362 # IEMOP_MNEMONIC0(a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5363 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0');
5364 if asArgs is not None:
5365 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], []);
5366 # IEMOP_MNEMONIC1(a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5367 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1');
5368 if asArgs is not None:
5369 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[5], asArgs[6], [asArgs[4],]);
5370 # IEMOP_MNEMONIC2(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5371 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2');
5372 if asArgs is not None:
5373 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[6], asArgs[7],
5374 [asArgs[4], asArgs[5],]);
5375 # IEMOP_MNEMONIC3(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints, a_fIemHints)
5376 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3');
5377 if asArgs is not None:
5378 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[7], asArgs[8],
5379 [asArgs[4], asArgs[5], asArgs[6],]);
5380 # IEMOP_MNEMONIC4(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints, a_fIemHints)
5381 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4');
5382 if asArgs is not None:
5383 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[8], asArgs[9],
5384 [asArgs[4], asArgs[5], asArgs[6], asArgs[7],]);
5385
5386 #
5387 # IEM_MC_BEGIN + IEM_MC_END.
5388 # We must support multiple instances per code snippet.
5389 #
5390 offCode = sCode.find('IEM_MC_');
5391 if offCode >= 0:
5392 for oMatch in self.oReMcBeginEnd.finditer(sCode, offCode):
5393 if oMatch.group(1) == 'END':
5394 self.workerIemMcEnd(offLine + oMatch.start());
5395 elif oMatch.group(1) == 'BEGIN':
5396 self.workerIemMcBegin(sCode, oMatch.start(), offLine + oMatch.start());
5397 else:
5398 self.workerIemMcDeferToCImplXRet(sCode, oMatch.start(), offLine + oMatch.start(),
5399 int(oMatch.group(1)[len('DEFER_TO_CIMPL_')]));
5400 return True;
5401
5402 return False;
5403
5404 def workerPreprocessorRecreateMacroRegex(self):
5405 """
5406 Recreates self.oReMacros when self.dMacros changes.
5407 """
5408 if self.dMacros:
5409 sRegex = '';
5410 for sName, oMacro in self.dMacros.items():
5411 if sRegex:
5412 sRegex += '|' + sName;
5413 else:
5414 sRegex = '\\b(' + sName;
5415 if oMacro.asArgs is not None:
5416 sRegex += '\s*\(';
5417 else:
5418 sRegex += '\\b';
5419 sRegex += ')';
5420 self.oReMacros = re.compile(sRegex);
5421 else:
5422 self.oReMacros = None;
5423 return True;
5424
5425 def workerPreprocessorDefine(self, sRest):
5426 """
5427 Handles a macro #define, the sRest is what follows after the directive word.
5428 """
5429 assert sRest[-1] == '\n';
5430
5431 #
5432 # If using line continutation, just concat all the lines together,
5433 # preserving the newline character but not the escaping.
5434 #
5435 iLineStart = self.iLine;
5436 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
5437 sRest = sRest[0:-2].rstrip() + '\n' + self.asLines[self.iLine];
5438 self.iLine += 1;
5439 #self.debug('workerPreprocessorDefine: sRest=%s<EOS>' % (sRest,));
5440
5441 #
5442 # Use regex to split out the name, argument list and body.
5443 # If this fails, we assume it's a simple macro.
5444 #
5445 oMatch = self.oReHashDefine2.match(sRest);
5446 if oMatch:
5447 sAllArgs = oMatch.group(2).strip();
5448 asArgs = [sParam.strip() for sParam in sAllArgs.split(',')] if sAllArgs else None;
5449 sBody = oMatch.group(3);
5450 else:
5451 oMatch = self.oReHashDefine3.match(sRest);
5452 if not oMatch:
5453 self.debug('workerPreprocessorDefine: wtf? sRest=%s' % (sRest,));
5454 return self.error('bogus macro definition: %s' % (sRest,));
5455 asArgs = None;
5456 sBody = oMatch.group(2);
5457 sName = oMatch.group(1);
5458 assert sName == sName.strip();
5459 #self.debug('workerPreprocessorDefine: sName=%s asArgs=%s sBody=%s<EOS>' % (sName, asArgs, sBody));
5460
5461 #
5462 # Is this of any interest to us? We do NOT support MC blocks wihtin
5463 # nested macro expansion, just to avoid lots of extra work.
5464 #
5465 # There is only limited support for macros expanding to partial MC blocks.
5466 #
5467 # Note! IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX and other macros someone making
5468 # use of IEMOP_RAISE_INVALID_LOCK_PREFIX_RET() will be ignored here and
5469 # dealt with by overriding IEMOP_RAISE_INVALID_LOCK_PREFIX_RET and its
5470 # siblings in the recompiler. This is a lot simpler than nested macro
5471 # expansion and lots of heuristics for locating all the relevant macros.
5472 # Also, this way we don't produce lots of unnecessary threaded functions.
5473 #
5474 if sBody.find("IEM_MC_BEGIN") < 0 and sBody.find("IEM_MC_END") < 0:
5475 #self.debug('workerPreprocessorDefine: irrelevant (%s: %s)' % (sName, sBody));
5476 return True;
5477
5478 #
5479 # Add the macro.
5480 #
5481 if self.fDebugPreproc:
5482 self.debug('#define %s on line %u' % (sName, self.iLine,));
5483 self.dMacros[sName] = SimpleParser.Macro(sName, asArgs, sBody.strip(), iLineStart);
5484 return self.workerPreprocessorRecreateMacroRegex();
5485
5486 def workerPreprocessorUndef(self, sRest):
5487 """
5488 Handles a macro #undef, the sRest is what follows after the directive word.
5489 """
5490 # Quick comment strip and isolate the name.
5491 offSlash = sRest.find('/');
5492 if offSlash > 0:
5493 sRest = sRest[:offSlash];
5494 sName = sRest.strip();
5495
5496 # Remove the macro if we're clocking it.
5497 if sName in self.dMacros:
5498 if self.fDebugPreproc:
5499 self.debug('#undef %s on line %u' % (sName, self.iLine,));
5500 del self.dMacros[sName];
5501 return self.workerPreprocessorRecreateMacroRegex();
5502
5503 return True;
5504
5505 def workerPreprocessorIfOrElif(self, sDirective, sRest):
5506 """
5507 Handles an #if, #ifdef, #ifndef or #elif directive.
5508 """
5509 #
5510 # Sanity check #elif.
5511 #
5512 if sDirective == 'elif':
5513 if len(self.aoCppCondStack) == 0:
5514 self.raiseError('#elif without #if');
5515 if self.aoCppCondStack[-1].fInElse:
5516 self.raiseError('#elif after #else');
5517
5518 #
5519 # If using line continutation, just concat all the lines together,
5520 # stripping both the newline and escape characters.
5521 #
5522 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
5523 sRest = sRest[0:-2].rstrip() + ' ' + self.asLines[self.iLine];
5524 self.iLine += 1;
5525
5526 # Strip it of all comments and leading and trailing blanks.
5527 sRest = self.stripComments(sRest).strip();
5528
5529 #
5530 # Stash it.
5531 #
5532 try:
5533 oPreprocCond = self.PreprocessorConditional(sDirective, sRest);
5534 except Exception as oXcpt:
5535 self.raiseError(oXcpt.args[0]);
5536
5537 if sDirective == 'elif':
5538 self.aoCppCondStack[-1].aoElif.append(oPreprocCond);
5539 else:
5540 self.aoCppCondStack.append(oPreprocCond);
5541
5542 return True;
5543
5544 def workerPreprocessorElse(self):
5545 """
5546 Handles an #else directive.
5547 """
5548 if len(self.aoCppCondStack) == 0:
5549 self.raiseError('#else without #if');
5550 if self.aoCppCondStack[-1].fInElse:
5551 self.raiseError('Another #else after #else');
5552
5553 self.aoCppCondStack[-1].fInElse = True;
5554 return True;
5555
5556 def workerPreprocessorEndif(self):
5557 """
5558 Handles an #endif directive.
5559 """
5560 if len(self.aoCppCondStack) == 0:
5561 self.raiseError('#endif without #if');
5562
5563 self.aoCppCondStack.pop();
5564 return True;
5565
5566 def checkPreprocessorDirective(self, sLine):
5567 """
5568 Handles a preprocessor directive.
5569 """
5570 # Skip past the preprocessor hash.
5571 off = sLine.find('#');
5572 assert off >= 0;
5573 off += 1;
5574 while off < len(sLine) and sLine[off].isspace():
5575 off += 1;
5576
5577 # Extract the directive.
5578 offDirective = off;
5579 while off < len(sLine) and not sLine[off].isspace():
5580 off += 1;
5581 sDirective = sLine[offDirective:off];
5582 if self.fDebugPreproc:
5583 self.debug('line %d: #%s...' % (self.iLine, sDirective));
5584
5585 # Skip spaces following it to where the arguments/whatever starts.
5586 while off + 1 < len(sLine) and sLine[off + 1].isspace():
5587 off += 1;
5588 sTail = sLine[off:];
5589
5590 # Handle the directive.
5591 if sDirective == 'define':
5592 return self.workerPreprocessorDefine(sTail);
5593 if sDirective == 'undef':
5594 return self.workerPreprocessorUndef(sTail);
5595 if sDirective in ('if', 'ifdef', 'ifndef', 'elif',):
5596 return self.workerPreprocessorIfOrElif(sDirective, sTail);
5597 if sDirective == 'else':
5598 return self.workerPreprocessorElse();
5599 if sDirective == 'endif':
5600 return self.workerPreprocessorEndif();
5601
5602 if self.fDebugPreproc:
5603 self.debug('line %d: Unknown preprocessor directive: %s' % (self.iLine, sDirective));
5604 return False;
5605
5606 def expandMacros(self, sLine, oMatch):
5607 """
5608 Expands macros we know about in the given line.
5609 Currently we ASSUME there is only one and that is what oMatch matched.
5610 """
5611 #
5612 # Get our bearings.
5613 #
5614 offMatch = oMatch.start();
5615 sName = oMatch.group(1);
5616 assert sName == sLine[oMatch.start() : oMatch.end()];
5617 fWithArgs = sName.endswith('(');
5618 if fWithArgs:
5619 sName = sName[:-1].strip();
5620 oMacro = self.dMacros[sName] # type: SimpleParser.Macro
5621
5622 #
5623 # Deal with simple macro invocations w/o parameters.
5624 #
5625 if not fWithArgs:
5626 if self.fDebugPreproc:
5627 self.debug('expanding simple macro %s on line %u' % (sName, self.iLine,));
5628 return sLine[:offMatch] + oMacro.expandMacro(self) + sLine[oMatch.end():];
5629
5630 #
5631 # Complicated macro with parameters.
5632 # Start by extracting the parameters. ASSUMES they are all on the same line!
5633 #
5634 cLevel = 1;
5635 offCur = oMatch.end();
5636 offCurArg = offCur;
5637 asArgs = [];
5638 while True:
5639 if offCur >= len(sLine):
5640 self.raiseError('expandMacros: Invocation of macro %s spans multiple lines!' % (sName,));
5641 ch = sLine[offCur];
5642 if ch == '(':
5643 cLevel += 1;
5644 elif ch == ')':
5645 cLevel -= 1;
5646 if cLevel == 0:
5647 asArgs.append(sLine[offCurArg:offCur].strip());
5648 break;
5649 elif ch == ',' and cLevel == 1:
5650 asArgs.append(sLine[offCurArg:offCur].strip());
5651 offCurArg = offCur + 1;
5652 offCur += 1;
5653 if len(oMacro.asArgs) == 0 and len(asArgs) == 1 and asArgs[0] == '': # trick for empty parameter list.
5654 asArgs = [];
5655 if len(oMacro.asArgs) != len(asArgs):
5656 self.raiseError('expandMacros: Argument mismatch in %s invocation' % (oMacro.sName,));
5657
5658 #
5659 # Do the expanding.
5660 #
5661 if self.fDebugPreproc:
5662 self.debug('expanding macro %s on line %u with arguments %s' % (sName, self.iLine, asArgs));
5663 return sLine[:offMatch] + oMacro.expandMacro(self, asArgs) + sLine[offCur + 1 :];
5664
5665 def parse(self):
5666 """
5667 Parses the given file.
5668
5669 Returns number or errors.
5670 Raises exception on fatal trouble.
5671 """
5672 #self.debug('Parsing %s' % (self.sSrcFile,));
5673
5674 #
5675 # Loop thru the lines.
5676 #
5677 # Please mind that self.iLine may be updated by checkCodeForMacro and
5678 # other worker methods.
5679 #
5680 while self.iLine < len(self.asLines):
5681 sLine = self.asLines[self.iLine];
5682 self.iLine += 1;
5683 #self.debug('line %u: %s' % (self.iLine, sLine[:-1]));
5684
5685 # Expand macros we know about if we're currently in code.
5686 if self.iState == self.kiCode and self.oReMacros:
5687 oMatch = self.oReMacros.search(sLine);
5688 if oMatch:
5689 sLine = self.expandMacros(sLine, oMatch);
5690 if self.fDebugPreproc:
5691 self.debug('line %d: expanded\n%s ==>\n%s' % (self.iLine, self.asLines[self.iLine - 1], sLine[:-1],));
5692 self.asLines[self.iLine - 1] = sLine;
5693
5694 # Check for preprocessor directives before comments and other stuff.
5695 # ASSUMES preprocessor directives doesn't end with multiline comments.
5696 if self.iState == self.kiCode and sLine.lstrip().startswith('#'):
5697 if self.fDebugPreproc:
5698 self.debug('line %d: preproc' % (self.iLine,));
5699 self.checkPreprocessorDirective(sLine);
5700 else:
5701 # Look for comments.
5702 offSlash = sLine.find('/');
5703 if offSlash >= 0:
5704 if offSlash + 1 >= len(sLine) or sLine[offSlash + 1] != '/' or self.iState != self.kiCode:
5705 offLine = 0;
5706 while offLine < len(sLine):
5707 if self.iState == self.kiCode:
5708 # Look for substantial multiline comment so we pass the following MC as a whole line:
5709 # IEM_MC_ARG_CONST(uint8_t, bImmArg, /*=*/ bImm, 2);
5710 # Note! We ignore C++ comments here, assuming these aren't used in lines with C-style comments.
5711 offHit = sLine.find('/*', offLine);
5712 while offHit >= 0:
5713 offEnd = sLine.find('*/', offHit + 2);
5714 if offEnd < 0 or offEnd - offHit >= 16: # 16 chars is a bit random.
5715 break;
5716 offHit = sLine.find('/*', offEnd);
5717
5718 if offHit >= 0:
5719 self.checkCodeForMacro(sLine[offLine:offHit], offLine);
5720 self.sComment = '';
5721 self.iCommentLine = self.iLine;
5722 self.iState = self.kiCommentMulti;
5723 offLine = offHit + 2;
5724 else:
5725 self.checkCodeForMacro(sLine[offLine:], offLine);
5726 offLine = len(sLine);
5727
5728 elif self.iState == self.kiCommentMulti:
5729 offHit = sLine.find('*/', offLine);
5730 if offHit >= 0:
5731 self.sComment += sLine[offLine:offHit];
5732 self.iState = self.kiCode;
5733 offLine = offHit + 2;
5734 self.parseComment();
5735 else:
5736 self.sComment += sLine[offLine:];
5737 offLine = len(sLine);
5738 else:
5739 assert False;
5740 # C++ line comment.
5741 elif offSlash > 0:
5742 self.checkCodeForMacro(sLine[:offSlash], 0);
5743
5744 # No slash, but append the line if in multi-line comment.
5745 elif self.iState == self.kiCommentMulti:
5746 #self.debug('line %d: multi' % (self.iLine,));
5747 self.sComment += sLine;
5748
5749 # No slash, but check code line for relevant macro.
5750 elif ( self.iState == self.kiCode
5751 and (sLine.find('IEMOP_') >= 0 or sLine.find('FNIEMOPRM_DEF') >= 0 or sLine.find('IEM_MC') >= 0)):
5752 #self.debug('line %d: macro' % (self.iLine,));
5753 self.checkCodeForMacro(sLine, 0);
5754
5755 # If the line is a '}' in the first position, complete the instructions.
5756 elif self.iState == self.kiCode and sLine[0] == '}':
5757 #self.debug('line %d: }' % (self.iLine,));
5758 self.doneInstructions(fEndOfFunction = True);
5759
5760 # Look for instruction table on the form 'IEM_STATIC const PFNIEMOP g_apfnVexMap3'
5761 # so we can check/add @oppfx info from it.
5762 elif self.iState == self.kiCode and sLine.find('PFNIEMOP') > 0 and self.oReFunTable.match(sLine):
5763 self.parseFunctionTable(sLine);
5764
5765 self.doneInstructions(fEndOfFunction = True);
5766 self.debug('%3s%% / %3s stubs out of %4s instructions and %4s MC blocks in %s'
5767 % (self.cTotalStubs * 100 // max(self.cTotalInstr, 1), self.cTotalStubs, self.cTotalInstr,
5768 self.cTotalMcBlocks, os.path.basename(self.sSrcFile),));
5769 return self.printErrors();
5770
5771## The parsed content of IEMAllInstCommonBodyMacros.h.
5772g_oParsedCommonBodyMacros = None # type: SimpleParser
5773
5774def __parseFileByName(sSrcFile, sDefaultMap, sHostArch):
5775 """
5776 Parses one source file for instruction specfications.
5777 """
5778 #
5779 # Read sSrcFile into a line array.
5780 #
5781 try:
5782 oFile = open(sSrcFile, "r"); # pylint: disable=consider-using-with,unspecified-encoding
5783 except Exception as oXcpt:
5784 raise Exception("failed to open %s for reading: %s" % (sSrcFile, oXcpt,));
5785 try:
5786 asLines = oFile.readlines();
5787 except Exception as oXcpt:
5788 raise Exception("failed to read %s: %s" % (sSrcFile, oXcpt,));
5789 finally:
5790 oFile.close();
5791
5792 #
5793 # On the first call, we parse IEMAllInstCommonBodyMacros.h so we
5794 # can use the macros from it when processing the other files.
5795 #
5796 global g_oParsedCommonBodyMacros;
5797 if g_oParsedCommonBodyMacros is None:
5798 # Locate the file.
5799 sCommonBodyMacros = os.path.join(os.path.split(sSrcFile)[0], 'IEMAllInstCommonBodyMacros.h');
5800 if not os.path.isfile(sCommonBodyMacros):
5801 sCommonBodyMacros = os.path.join(os.path.split(__file__)[0], 'IEMAllInstCommonBodyMacros.h');
5802
5803 # Read it.
5804 try:
5805 with open(sCommonBodyMacros, "r") as oIncFile: # pylint: disable=unspecified-encoding
5806 asIncFiles = oIncFile.readlines();
5807 except Exception as oXcpt:
5808 raise Exception("failed to open/read %s: %s" % (sCommonBodyMacros, oXcpt,));
5809
5810 # Parse it.
5811 try:
5812 oParser = SimpleParser(sCommonBodyMacros, asIncFiles, 'one', sHostArch);
5813 if oParser.parse() != 0:
5814 raise ParserException('%s: errors: See above' % (sCommonBodyMacros, ));
5815 if oParser.cTotalInstr != 0 or oParser.cTotalStubs != 0 or oParser.cTotalTagged != 0 or oParser.cTotalMcBlocks != 0:
5816 raise ParserException('%s: error: Unexpectedly found %u instr, %u tags, %u stubs and %u MCs, expecting zero. %s'
5817 % (sCommonBodyMacros, oParser.cTotalInstr, oParser.cTotalStubs, oParser.cTotalTagged,
5818 oParser.cTotalMcBlocks,
5819 ', '.join(sorted( [str(oMcBlock.iBeginLine) for oMcBlock in g_aoMcBlocks]
5820 + [str(oInstr.iLineCreated) for oInstr in g_aoAllInstructions])),));
5821 except ParserException as oXcpt:
5822 print(str(oXcpt), file = sys.stderr);
5823 raise;
5824 g_oParsedCommonBodyMacros = oParser;
5825
5826 #
5827 # Do the parsing.
5828 #
5829 try:
5830 oParser = SimpleParser(sSrcFile, asLines, sDefaultMap, sHostArch, g_oParsedCommonBodyMacros);
5831 return (oParser.parse(), oParser) ;
5832 except ParserException as oXcpt:
5833 print(str(oXcpt), file = sys.stderr);
5834 raise;
5835
5836
5837def __doTestCopying():
5838 """
5839 Executes the asCopyTests instructions.
5840 """
5841 asErrors = [];
5842 for oDstInstr in g_aoAllInstructions:
5843 if oDstInstr.asCopyTests:
5844 for sSrcInstr in oDstInstr.asCopyTests:
5845 oSrcInstr = g_dAllInstructionsByStat.get(sSrcInstr, None);
5846 if oSrcInstr:
5847 aoSrcInstrs = [oSrcInstr,];
5848 else:
5849 aoSrcInstrs = g_dAllInstructionsByFunction.get(sSrcInstr, []);
5850 if aoSrcInstrs:
5851 for oSrcInstr in aoSrcInstrs:
5852 if oSrcInstr != oDstInstr:
5853 oDstInstr.aoTests.extend(oSrcInstr.aoTests);
5854 else:
5855 asErrors.append('%s:%s: error: @opcopytests reference "%s" matches the destination\n'
5856 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
5857 else:
5858 asErrors.append('%s:%s: error: @opcopytests reference "%s" not found\n'
5859 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
5860
5861 if asErrors:
5862 sys.stderr.write(u''.join(asErrors));
5863 return len(asErrors);
5864
5865
5866def __applyOnlyTest():
5867 """
5868 If g_aoOnlyTestInstructions contains any instructions, drop aoTests from
5869 all other instructions so that only these get tested.
5870 """
5871 if g_aoOnlyTestInstructions:
5872 for oInstr in g_aoAllInstructions:
5873 if oInstr.aoTests:
5874 if oInstr not in g_aoOnlyTestInstructions:
5875 oInstr.aoTests = [];
5876 return 0;
5877
5878## List of all main instruction files, their default maps and file sets (-1 means included it all sets).
5879g_aaoAllInstrFilesAndDefaultMapAndSet = (
5880 ( 'IEMAllInstCommon.cpp.h', 'one', -1, ),
5881 ( 'IEMAllInstOneByte.cpp.h', 'one', 1, ),
5882 ( 'IEMAllInst3DNow.cpp.h', '3dnow', 2, ),
5883 ( 'IEMAllInstTwoByte0f.cpp.h', 'two0f', 2, ),
5884 ( 'IEMAllInstThree0f38.cpp.h', 'three0f38', 3, ),
5885 ( 'IEMAllInstThree0f3a.cpp.h', 'three0f3a', 3, ),
5886 ( 'IEMAllInstVexMap1.cpp.h', 'vexmap1', 4, ),
5887 ( 'IEMAllInstVexMap2.cpp.h', 'vexmap2', 4, ),
5888 ( 'IEMAllInstVexMap3.cpp.h', 'vexmap3', 4, ),
5889);
5890
5891def __parseFilesWorker(asFilesAndDefaultMap, sHostArch):
5892 """
5893 Parses all the IEMAllInstruction*.cpp.h files.
5894
5895 Returns a list of the parsers on success.
5896 Raises exception on failure.
5897 """
5898 sSrcDir = os.path.dirname(os.path.abspath(__file__));
5899 cErrors = 0;
5900 aoParsers = [];
5901 for sFilename, sDefaultMap in asFilesAndDefaultMap:
5902 if not os.path.split(sFilename)[0] and not os.path.exists(sFilename):
5903 sFilename = os.path.join(sSrcDir, sFilename);
5904 cThisErrors, oParser = __parseFileByName(sFilename, sDefaultMap, sHostArch);
5905 cErrors += cThisErrors;
5906 aoParsers.append(oParser);
5907 cErrors += __doTestCopying();
5908 cErrors += __applyOnlyTest();
5909
5910 # Total stub stats:
5911 cTotalStubs = 0;
5912 for oInstr in g_aoAllInstructions:
5913 cTotalStubs += oInstr.fStub;
5914 print('debug: %3s%% / %3s stubs out of %4s instructions and %4s MC blocks in total'
5915 % (cTotalStubs * 100 // len(g_aoAllInstructions), cTotalStubs, len(g_aoAllInstructions), len(g_aoMcBlocks),),
5916 file = sys.stderr);
5917
5918 if cErrors != 0:
5919 raise Exception('%d parse errors' % (cErrors,));
5920 return aoParsers;
5921
5922
5923def parseFiles(asFiles, sHostArch = None):
5924 """
5925 Parses a selection of IEMAllInstruction*.cpp.h files.
5926
5927 Returns a list of the parsers on success.
5928 Raises exception on failure.
5929 """
5930 # Look up default maps for the files and call __parseFilesWorker to do the job.
5931 asFilesAndDefaultMap = [];
5932 for sFilename in asFiles:
5933 sName = os.path.split(sFilename)[1].lower();
5934 sMap = None;
5935 for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet:
5936 if aoInfo[0].lower() == sName:
5937 sMap = aoInfo[1];
5938 break;
5939 if not sMap:
5940 raise Exception('Unable to classify file: %s' % (sFilename,));
5941 asFilesAndDefaultMap.append((sFilename, sMap));
5942
5943 return __parseFilesWorker(asFilesAndDefaultMap, sHostArch);
5944
5945
5946def parseAll(sHostArch = None):
5947 """
5948 Parses all the IEMAllInstruction*.cpp.h files.
5949
5950 Returns a list of the parsers on success.
5951 Raises exception on failure.
5952 """
5953 return __parseFilesWorker([aoInfo[0:2] for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet], sHostArch);
5954
5955
5956#
5957# Generators (may perhaps move later).
5958#
5959def __formatDisassemblerTableEntry(oInstr):
5960 """
5961 """
5962 sMacro = 'OP';
5963 cMaxOperands = 3;
5964 if len(oInstr.aoOperands) > 3:
5965 sMacro = 'OPVEX'
5966 cMaxOperands = 4;
5967 assert len(oInstr.aoOperands) <= cMaxOperands;
5968
5969 #
5970 # Format string.
5971 #
5972 sTmp = '%s("%s' % (sMacro, oInstr.sMnemonic,);
5973 for iOperand, oOperand in enumerate(oInstr.aoOperands):
5974 sTmp += ' ' if iOperand == 0 else ',';
5975 if g_kdOpTypes[oOperand.sType][2][0] != '%': ## @todo remove upper() later.
5976 sTmp += g_kdOpTypes[oOperand.sType][2].upper(); ## @todo remove upper() later.
5977 else:
5978 sTmp += g_kdOpTypes[oOperand.sType][2];
5979 sTmp += '",';
5980 asColumns = [ sTmp, ];
5981
5982 #
5983 # Decoders.
5984 #
5985 iStart = len(asColumns);
5986 if oInstr.sEncoding is None:
5987 pass;
5988 elif oInstr.sEncoding == 'ModR/M':
5989 # ASSUME the first operand is using the ModR/M encoding
5990 assert len(oInstr.aoOperands) >= 1 and oInstr.aoOperands[0].usesModRM(), "oInstr=%s" % (oInstr,);
5991 asColumns.append('IDX_ParseModRM,');
5992 elif oInstr.sEncoding in [ 'prefix', ]:
5993 for oOperand in oInstr.aoOperands:
5994 asColumns.append('0,');
5995 elif oInstr.sEncoding in [ 'fixed', 'VEX.fixed' ]:
5996 pass;
5997 elif oInstr.sEncoding == 'VEX.ModR/M':
5998 asColumns.append('IDX_ParseModRM,');
5999 elif oInstr.sEncoding == 'vex2':
6000 asColumns.append('IDX_ParseVex2b,')
6001 elif oInstr.sEncoding == 'vex3':
6002 asColumns.append('IDX_ParseVex3b,')
6003 elif oInstr.sEncoding in g_dInstructionMaps:
6004 asColumns.append(g_dInstructionMaps[oInstr.sEncoding].sDisParse + ',');
6005 else:
6006 ## @todo
6007 #IDX_ParseTwoByteEsc,
6008 #IDX_ParseGrp1,
6009 #IDX_ParseShiftGrp2,
6010 #IDX_ParseGrp3,
6011 #IDX_ParseGrp4,
6012 #IDX_ParseGrp5,
6013 #IDX_Parse3DNow,
6014 #IDX_ParseGrp6,
6015 #IDX_ParseGrp7,
6016 #IDX_ParseGrp8,
6017 #IDX_ParseGrp9,
6018 #IDX_ParseGrp10,
6019 #IDX_ParseGrp12,
6020 #IDX_ParseGrp13,
6021 #IDX_ParseGrp14,
6022 #IDX_ParseGrp15,
6023 #IDX_ParseGrp16,
6024 #IDX_ParseThreeByteEsc4,
6025 #IDX_ParseThreeByteEsc5,
6026 #IDX_ParseModFence,
6027 #IDX_ParseEscFP,
6028 #IDX_ParseNopPause,
6029 #IDX_ParseInvOpModRM,
6030 assert False, str(oInstr);
6031
6032 # Check for immediates and stuff in the remaining operands.
6033 for oOperand in oInstr.aoOperands[len(asColumns) - iStart:]:
6034 sIdx = g_kdOpTypes[oOperand.sType][0];
6035 #if sIdx != 'IDX_UseModRM':
6036 asColumns.append(sIdx + ',');
6037 asColumns.extend(['0,'] * (cMaxOperands - (len(asColumns) - iStart)));
6038
6039 #
6040 # Opcode and operands.
6041 #
6042 assert oInstr.sDisEnum, str(oInstr);
6043 asColumns.append(oInstr.sDisEnum + ',');
6044 iStart = len(asColumns)
6045 for oOperand in oInstr.aoOperands:
6046 asColumns.append('OP_PARM_' + g_kdOpTypes[oOperand.sType][3] + ',');
6047 asColumns.extend(['OP_PARM_NONE,'] * (cMaxOperands - (len(asColumns) - iStart)));
6048
6049 #
6050 # Flags.
6051 #
6052 sTmp = '';
6053 for sHint in sorted(oInstr.dHints.keys()):
6054 sDefine = g_kdHints[sHint];
6055 if sDefine.startswith('DISOPTYPE_'):
6056 if sTmp:
6057 sTmp += ' | ' + sDefine;
6058 else:
6059 sTmp += sDefine;
6060 if sTmp:
6061 sTmp += '),';
6062 else:
6063 sTmp += '0),';
6064 asColumns.append(sTmp);
6065
6066 #
6067 # Format the columns into a line.
6068 #
6069 aoffColumns = [4, 29, 49, 65, 77, 89, 109, 125, 141, 157, 183, 199];
6070 sLine = '';
6071 for i, s in enumerate(asColumns):
6072 if len(sLine) < aoffColumns[i]:
6073 sLine += ' ' * (aoffColumns[i] - len(sLine));
6074 else:
6075 sLine += ' ';
6076 sLine += s;
6077
6078 # OP("psrlw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE,
6079 # DISOPTYPE_HARMLESS),
6080 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
6081 # { pszOpcode, idxParse1, idxParse2, idxParse3, 0, opcode, param1, param2, param3, 0, 0, optype }
6082 return sLine;
6083
6084def __checkIfShortTable(aoTableOrdered, oMap):
6085 """
6086 Returns (iInstr, cInstructions, fShortTable)
6087 """
6088
6089 # Determin how much we can trim off.
6090 cInstructions = len(aoTableOrdered);
6091 while cInstructions > 0 and aoTableOrdered[cInstructions - 1] is None:
6092 cInstructions -= 1;
6093
6094 iInstr = 0;
6095 while iInstr < cInstructions and aoTableOrdered[iInstr] is None:
6096 iInstr += 1;
6097
6098 # If we can save more than 30%, we go for the short table version.
6099 if iInstr + len(aoTableOrdered) - cInstructions >= len(aoTableOrdered) // 30:
6100 return (iInstr, cInstructions, True);
6101 _ = oMap; # Use this for overriding.
6102
6103 # Output the full table.
6104 return (0, len(aoTableOrdered), False);
6105
6106def generateDisassemblerTables(oDstFile = sys.stdout):
6107 """
6108 Generates disassembler tables.
6109
6110 Returns exit code.
6111 """
6112
6113 #
6114 # Parse all.
6115 #
6116 try:
6117 parseAll();
6118 except Exception as oXcpt:
6119 print('error: parseAll failed: %s' % (oXcpt,), file = sys.stderr);
6120 traceback.print_exc(file = sys.stderr);
6121 return 1;
6122
6123
6124 #
6125 # The disassembler uses a slightly different table layout to save space,
6126 # since several of the prefix varia
6127 #
6128 aoDisasmMaps = [];
6129 for sName, oMap in sorted(iter(g_dInstructionMaps.items()),
6130 key = lambda aKV: aKV[1].sEncoding + ''.join(aKV[1].asLeadOpcodes)):
6131 if oMap.sSelector != 'byte+pfx':
6132 aoDisasmMaps.append(oMap);
6133 else:
6134 # Split the map by prefix.
6135 aoDisasmMaps.append(oMap.copy(oMap.sName, 'none'));
6136 aoDisasmMaps.append(oMap.copy(oMap.sName + '_66', '0x66'));
6137 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F3', '0xf3'));
6138 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F2', '0xf2'));
6139
6140 #
6141 # Dump each map.
6142 #
6143 asHeaderLines = [];
6144 print("debug: maps=%s\n" % (', '.join([oMap.sName for oMap in aoDisasmMaps]),), file = sys.stderr);
6145 for oMap in aoDisasmMaps:
6146 sName = oMap.sName;
6147
6148 if not sName.startswith("vex"): continue; # only looking at the vex maps at the moment.
6149
6150 #
6151 # Get the instructions for the map and see if we can do a short version or not.
6152 #
6153 aoTableOrder = oMap.getInstructionsInTableOrder();
6154 cEntriesPerByte = oMap.getEntriesPerByte();
6155 (iInstrStart, iInstrEnd, fShortTable) = __checkIfShortTable(aoTableOrder, oMap);
6156
6157 #
6158 # Output the table start.
6159 # Note! Short tables are static and only accessible via the map range record.
6160 #
6161 asLines = [];
6162 asLines.append('/* Generated from: %-11s Selector: %-7s Encoding: %-7s Lead bytes opcodes: %s */'
6163 % ( oMap.sName, oMap.sSelector, oMap.sEncoding, ' '.join(oMap.asLeadOpcodes), ));
6164 if fShortTable:
6165 asLines.append('%sconst DISOPCODE %s[] =' % ('static ' if fShortTable else '', oMap.getDisasTableName(),));
6166 else:
6167 asHeaderLines.append('extern const DISOPCODE %s[%d];' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6168 asLines.append( 'const DISOPCODE %s[%d] =' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6169 asLines.append('{');
6170
6171 if fShortTable and (iInstrStart & ((0x10 * cEntriesPerByte) - 1)) != 0:
6172 asLines.append(' /* %#04x: */' % (iInstrStart,));
6173
6174 #
6175 # Output the instructions.
6176 #
6177 iInstr = iInstrStart;
6178 while iInstr < iInstrEnd:
6179 oInstr = aoTableOrder[iInstr];
6180 if (iInstr & ((0x10 * cEntriesPerByte) - 1)) == 0:
6181 if iInstr != iInstrStart:
6182 asLines.append('');
6183 asLines.append(' /* %x */' % ((iInstr // cEntriesPerByte) >> 4,));
6184
6185 if oInstr is None:
6186 # Invalid. Optimize blocks of invalid instructions.
6187 cInvalidInstrs = 1;
6188 while iInstr + cInvalidInstrs < len(aoTableOrder) and aoTableOrder[iInstr + cInvalidInstrs] is None:
6189 cInvalidInstrs += 1;
6190 if (iInstr & (0x10 * cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= 0x10 * cEntriesPerByte:
6191 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (0x10 * cEntriesPerByte,));
6192 iInstr += 0x10 * cEntriesPerByte - 1;
6193 elif cEntriesPerByte > 1:
6194 if (iInstr & (cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= cEntriesPerByte:
6195 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (cEntriesPerByte,));
6196 iInstr += 3;
6197 else:
6198 asLines.append(' /* %#04x/%d */ INVALID_OPCODE,'
6199 % (iInstr // cEntriesPerByte, iInstr % cEntriesPerByte));
6200 else:
6201 asLines.append(' /* %#04x */ INVALID_OPCODE,' % (iInstr));
6202 elif isinstance(oInstr, list):
6203 if len(oInstr) != 0:
6204 asLines.append(' /* %#04x */ ComplicatedListStuffNeedingWrapper, /* \n -- %s */'
6205 % (iInstr, '\n -- '.join([str(oItem) for oItem in oInstr]),));
6206 else:
6207 asLines.append(__formatDisassemblerTableEntry(oInstr));
6208 else:
6209 asLines.append(__formatDisassemblerTableEntry(oInstr));
6210
6211 iInstr += 1;
6212
6213 if iInstrStart >= iInstrEnd:
6214 asLines.append(' /* dummy */ INVALID_OPCODE');
6215
6216 asLines.append('};');
6217 asLines.append('AssertCompile(RT_ELEMENTS(%s) == %s);' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6218
6219 #
6220 # We always emit a map range record, assuming the linker will eliminate the unnecessary ones.
6221 #
6222 asHeaderLines.append('extern const DISOPMAPDESC %sRange;' % (oMap.getDisasRangeName()));
6223 asLines.append('const DISOPMAPDESC %s = { &%s[0], %#04x, RT_ELEMENTS(%s) };'
6224 % (oMap.getDisasRangeName(), oMap.getDisasTableName(), iInstrStart, oMap.getDisasTableName(),));
6225
6226 #
6227 # Write out the lines.
6228 #
6229 oDstFile.write('\n'.join(asLines));
6230 oDstFile.write('\n');
6231 oDstFile.write('\n');
6232 #break; #for now
6233 return 0;
6234
6235if __name__ == '__main__':
6236 sys.exit(generateDisassemblerTables());
6237
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