VirtualBox

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

Last change on this file since 105844 was 105664, checked in by vboxsync, 4 months ago

VMM/IEM: Implement vgather[dq]p[sd], vpgather[dq][dq] instruction decoding, dispatch & emulation, bugref:9898
VMM/IEM: Fix disassembly metadata for vpsllvq, vpsrlvq instructions
VMM/IEM: Adds MVx VSIB operand handling
VMM/IEM: Adds iemMemFetchDataU32NoAc(), iemMemFetchDataU64NoAc() unaligned memory fetchers

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

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