VirtualBox

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

Last change on this file since 106082 was 106061, checked in by vboxsync, 4 months ago

Copyright year updates by scm.

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