VirtualBox

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

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

VMM/IEM: Fix bound instruction emulation when running in the recompiler on ARM, bugref:10741

The bs3-cpu-generated-1 testcase would fail on the bound instruction when running in the recompiler because
input values are not properly sign extended to 32-bit on ARM before being passed to iemCImpl_bound_16 because the IEM MC block
for bound treated everything as uint16_t. This works with the interpreter because the function definition is int16_t so the
compiler does the proper sign extension but with our own recompiler we would end up with negative values not being properly sign extended.

Create some new IEM MC statements for signed values to make it easier to get things right in the future instead
of just making the iemCImpl_bound_16() take uint16_t and cast the values to int16_t in it.

On a funny side note, lldb prints the correct negative values for the int16_t in iemCImpl_bound_16(), so these can't be trusted, the registers
show the real values:

(lldb) register read
General Purpose Registers:

x0 = 0x000000011653c000
x1 = 0x0000000000000004
x2 = 0x000000000000ffff <= Wrong index, should be 0x00000000ffffffff
x3 = 0x000000000000fffe <= Wrong lower bound, should be 0x00000000fffffffe
x4 = 0x0000000000000000 <= Upper bound

[...]
(lldb) stepi
Process 31449 stopped

  • thread #22, name = 'EMT', stop reason = instruction step into

frame #0: 0x0000000132b242e4 VBoxVMM.dylib`::iemCImpl_bound_16(pVCpu=0x000000011653c000, cbInstr='\x04', idxArray=-1, idxLowerBound=-2, idxUpperBound=0) at IEMAllCImpl.cpp:8304:9 [opt]

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