VirtualBox

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

Last change on this file since 105904 was 105853, checked in by vboxsync, 7 months ago

VMM/IEM: Don't force PC updating before branches, nor flushing of dirty guest shadowed registers either. Both needs more work before todo 4 in bugref:10720 can be marked as resolved. bugref:10373 bugref:10629

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