VirtualBox

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

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

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

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