VirtualBox

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

Last change on this file since 101369 was 101369, checked in by vboxsync, 19 months ago

Main/Global.cpp: Move the macros for compose the x64/x86/arm64/arm32 guest OS IDs to the VirtualBox API header so the GUI and others can make use of them as well. bugref:10384

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

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