VirtualBox

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

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

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

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