VirtualBox

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

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

VMM/IEM: Native translation of IEM_MC_FETCH_FCW() body, bugref:10371

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