VirtualBox

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

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

VMM/IEM: Added a new class of threaded function variants, the 16f/32f/64f variants that will clear RF (and vbox internal friends) and check for TF (and vbox internal friends). The variants w/o the 'f' after the bitcount will skip this test+branch. The motivation of this was to deal with this issue that the threaded recompiler level rather than try optimize away the test+branch++ code when generating native code, make the IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32 a very simple place to start emitting native code (compared to IEM_MC_ADVANCE_RIP_AND_FINISH_THREADED_PC32_WITH_FLAGS). bugref:10371

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