VirtualBox

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

Last change on this file since 103613 was 103613, checked in by vboxsync, 9 months ago

VMM/IEM: Experimental code for emitting native code instead of calling AImpl helper, experimenting on: xor reg32,reg32. bugref:10376

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