VirtualBox

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

Last change on this file since 102977 was 102977, checked in by vboxsync, 10 months ago

VMM/IEM: Implemented generic fallback for misaligned x86 locking that is not compatible with the host. Using the existing split-lock solution with VINF_EM_EMULATE_SPLIT_LOCK from bugref:10052. We keep ignoring the 'lock' prefix in the recompiler for single CPU VMs (now also on amd64 hosts). bugref:10547

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

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