VirtualBox

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

最後變更 在這個檔案從103185是 103185,由 vboxsync 提交於 14 月 前

VMM/IEMAllInst*: Liveness analysis, part 2: Flag input & modification annotations. bugref:10372

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

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