VirtualBox

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

Last change on this file since 103025 was 102978, 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). [build fixes] 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.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllInstPython.py 102978 2024-01-19 23:19:05Z 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: 102978 $"
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}"
2790# pylint: disable=line-too-long
2791g_dMcStmtParsers = {
2792 'IEM_MC_ACTUALIZE_AVX_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, True, ),
2793 'IEM_MC_ACTUALIZE_AVX_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, True, ),
2794 'IEM_MC_ACTUALIZE_FPU_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, True, ),
2795 'IEM_MC_ACTUALIZE_FPU_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, True, ),
2796 'IEM_MC_ACTUALIZE_SSE_STATE_FOR_CHANGE': (McBlock.parseMcGeneric, False, False, True, ),
2797 'IEM_MC_ACTUALIZE_SSE_STATE_FOR_READ': (McBlock.parseMcGeneric, False, False, True, ),
2798 'IEM_MC_ADD_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
2799 'IEM_MC_ADD_GREG_U16_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
2800 'IEM_MC_ADD_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
2801 'IEM_MC_ADD_GREG_U32_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
2802 'IEM_MC_ADD_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
2803 'IEM_MC_ADD_GREG_U64_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
2804 'IEM_MC_ADD_GREG_U8_TO_LOCAL': (McBlock.parseMcGeneric, False, False, False, ),
2805 'IEM_MC_ADD_LOCAL_S16_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, True, False, ),
2806 'IEM_MC_ADD_LOCAL_S32_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, True, False, ),
2807 'IEM_MC_ADD_LOCAL_S64_TO_EFF_ADDR': (McBlock.parseMcGeneric, True, True, False, ),
2808 'IEM_MC_ADVANCE_RIP_AND_FINISH': (McBlock.parseMcGeneric, True, True, True, ),
2809 'IEM_MC_AND_2LOCS_U32': (McBlock.parseMcGeneric, False, False, False, ),
2810 'IEM_MC_AND_ARG_U16': (McBlock.parseMcGeneric, False, False, False, ),
2811 'IEM_MC_AND_ARG_U32': (McBlock.parseMcGeneric, False, False, False, ),
2812 'IEM_MC_AND_ARG_U64': (McBlock.parseMcGeneric, False, False, False, ),
2813 'IEM_MC_AND_GREG_U16': (McBlock.parseMcGeneric, True, True, False, ),
2814 'IEM_MC_AND_GREG_U32': (McBlock.parseMcGeneric, True, True, False, ),
2815 'IEM_MC_AND_GREG_U64': (McBlock.parseMcGeneric, True, True, False, ),
2816 'IEM_MC_AND_GREG_U8': (McBlock.parseMcGeneric, True, True, False, ),
2817 'IEM_MC_AND_LOCAL_U16': (McBlock.parseMcGeneric, False, False, False, ),
2818 'IEM_MC_AND_LOCAL_U32': (McBlock.parseMcGeneric, False, False, False, ),
2819 'IEM_MC_AND_LOCAL_U64': (McBlock.parseMcGeneric, False, False, False, ),
2820 'IEM_MC_AND_LOCAL_U8': (McBlock.parseMcGeneric, False, False, False, ),
2821 'IEM_MC_ARG': (McBlock.parseMcArg, False, False, True, ),
2822 'IEM_MC_ARG_CONST': (McBlock.parseMcArgConst, False, False, True, ),
2823 'IEM_MC_ARG_LOCAL_EFLAGS': (McBlock.parseMcArgLocalEFlags, False, False, True, ),
2824 'IEM_MC_ARG_LOCAL_REF': (McBlock.parseMcArgLocalRef, False, False, True, ),
2825 'IEM_MC_ASSIGN_TO_SMALLER': (McBlock.parseMcGeneric, False, False, True, ),
2826 'IEM_MC_BEGIN': (McBlock.parseMcBegin, False, False, True, ),
2827 'IEM_MC_BROADCAST_XREG_U16_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2828 'IEM_MC_BROADCAST_XREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2829 'IEM_MC_BROADCAST_XREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2830 'IEM_MC_BROADCAST_XREG_U8_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2831 'IEM_MC_BROADCAST_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2832 'IEM_MC_BROADCAST_YREG_U16_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2833 'IEM_MC_BROADCAST_YREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2834 'IEM_MC_BROADCAST_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2835 'IEM_MC_BROADCAST_YREG_U8_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2836 'IEM_MC_BSWAP_LOCAL_U16': (McBlock.parseMcGeneric, False, False, False, ),
2837 'IEM_MC_BSWAP_LOCAL_U32': (McBlock.parseMcGeneric, False, False, False, ),
2838 'IEM_MC_BSWAP_LOCAL_U64': (McBlock.parseMcGeneric, False, False, False, ),
2839 'IEM_MC_CALC_RM_EFF_ADDR': (McBlock.parseMcGeneric, False, False, False, ),
2840 'IEM_MC_CALL_AIMPL_3': (McBlock.parseMcCallAImpl, True, True, True, ),
2841 'IEM_MC_CALL_AIMPL_4': (McBlock.parseMcCallAImpl, True, True, True, ),
2842 'IEM_MC_CALL_AVX_AIMPL_2': (McBlock.parseMcCallAvxAImpl, True, True, False, ),
2843 'IEM_MC_CALL_AVX_AIMPL_3': (McBlock.parseMcCallAvxAImpl, True, True, False, ),
2844 'IEM_MC_CALL_CIMPL_0': (McBlock.parseMcCallCImpl, True, True, False, ),
2845 'IEM_MC_CALL_CIMPL_1': (McBlock.parseMcCallCImpl, True, True, False, ),
2846 'IEM_MC_CALL_CIMPL_2': (McBlock.parseMcCallCImpl, True, True, False, ),
2847 'IEM_MC_CALL_CIMPL_3': (McBlock.parseMcCallCImpl, True, True, False, ),
2848 'IEM_MC_CALL_CIMPL_4': (McBlock.parseMcCallCImpl, True, True, False, ),
2849 'IEM_MC_CALL_CIMPL_5': (McBlock.parseMcCallCImpl, True, True, False, ),
2850 'IEM_MC_CALL_FPU_AIMPL_1': (McBlock.parseMcCallFpuAImpl, True, True, False, ),
2851 'IEM_MC_CALL_FPU_AIMPL_2': (McBlock.parseMcCallFpuAImpl, True, True, False, ),
2852 'IEM_MC_CALL_FPU_AIMPL_3': (McBlock.parseMcCallFpuAImpl, True, True, False, ),
2853 'IEM_MC_CALL_MMX_AIMPL_2': (McBlock.parseMcCallMmxAImpl, True, True, False, ),
2854 'IEM_MC_CALL_MMX_AIMPL_3': (McBlock.parseMcCallMmxAImpl, True, True, False, ),
2855 'IEM_MC_CALL_SSE_AIMPL_2': (McBlock.parseMcCallSseAImpl, True, True, False, ),
2856 'IEM_MC_CALL_SSE_AIMPL_3': (McBlock.parseMcCallSseAImpl, True, True, False, ),
2857 'IEM_MC_CALL_VOID_AIMPL_0': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
2858 'IEM_MC_CALL_VOID_AIMPL_1': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
2859 'IEM_MC_CALL_VOID_AIMPL_2': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
2860 'IEM_MC_CALL_VOID_AIMPL_3': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
2861 'IEM_MC_CALL_VOID_AIMPL_4': (McBlock.parseMcCallVoidAImpl, True, True, True, ),
2862 'IEM_MC_CLEAR_EFL_BIT': (McBlock.parseMcGeneric, True, True, False, ),
2863 'IEM_MC_CLEAR_FSW_EX': (McBlock.parseMcGeneric, True, True, False, ),
2864 'IEM_MC_CLEAR_HIGH_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
2865 'IEM_MC_CLEAR_XREG_U32_MASK': (McBlock.parseMcGeneric, True, True, False, ),
2866 'IEM_MC_CLEAR_YREG_128_UP': (McBlock.parseMcGeneric, True, True, False, ),
2867 'IEM_MC_COMMIT_EFLAGS': (McBlock.parseMcGeneric, True, True, True, ),
2868 'IEM_MC_COPY_XREG_U128': (McBlock.parseMcGeneric, True, True, False, ),
2869 'IEM_MC_COPY_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2870 'IEM_MC_COPY_YREG_U256_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2871 'IEM_MC_COPY_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
2872 'IEM_MC_DEFER_TO_CIMPL_0_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
2873 'IEM_MC_DEFER_TO_CIMPL_1_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
2874 'IEM_MC_DEFER_TO_CIMPL_2_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
2875 'IEM_MC_DEFER_TO_CIMPL_3_RET': (McBlock.parseMcDeferToCImpl, False, False, False, ),
2876 'IEM_MC_END': (McBlock.parseMcGeneric, True, True, True, ),
2877 'IEM_MC_FETCH_EFLAGS': (McBlock.parseMcGeneric, False, False, True, ),
2878 'IEM_MC_FETCH_EFLAGS_U8': (McBlock.parseMcGeneric, False, False, False, ),
2879 'IEM_MC_FETCH_FCW': (McBlock.parseMcGeneric, False, False, False, ),
2880 'IEM_MC_FETCH_FSW': (McBlock.parseMcGeneric, False, False, False, ),
2881 'IEM_MC_FETCH_GREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
2882 'IEM_MC_FETCH_GREG_U16_SX_U32': (McBlock.parseMcGeneric, False, False, True, ),
2883 'IEM_MC_FETCH_GREG_U16_SX_U64': (McBlock.parseMcGeneric, False, False, True, ),
2884 'IEM_MC_FETCH_GREG_U16_ZX_U32': (McBlock.parseMcGeneric, False, False, True, ),
2885 'IEM_MC_FETCH_GREG_U16_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
2886 'IEM_MC_FETCH_GREG_U32': (McBlock.parseMcGeneric, False, False, True, ),
2887 'IEM_MC_FETCH_GREG_U32_SX_U64': (McBlock.parseMcGeneric, False, False, True, ),
2888 'IEM_MC_FETCH_GREG_U32_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
2889 'IEM_MC_FETCH_GREG_U64': (McBlock.parseMcGeneric, False, False, True, ),
2890 'IEM_MC_FETCH_GREG_U64_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
2891 'IEM_MC_FETCH_GREG_U8': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
2892 'IEM_MC_FETCH_GREG_U8_SX_U16': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
2893 'IEM_MC_FETCH_GREG_U8_SX_U32': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
2894 'IEM_MC_FETCH_GREG_U8_SX_U64': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
2895 'IEM_MC_FETCH_GREG_U8_ZX_U16': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
2896 'IEM_MC_FETCH_GREG_U8_ZX_U32': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
2897 'IEM_MC_FETCH_GREG_U8_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ), # thrd var
2898 'IEM_MC_FETCH_GREG_PAIR_U32': (McBlock.parseMcGeneric, False, False, False, ),
2899 'IEM_MC_FETCH_GREG_PAIR_U64': (McBlock.parseMcGeneric, False, False, False, ),
2900 'IEM_MC_FETCH_MEM_D80': (McBlock.parseMcGeneric, True, True, False, ),
2901 'IEM_MC_FETCH_MEM_I16': (McBlock.parseMcGeneric, True, True, False, ),
2902 'IEM_MC_FETCH_MEM_I32': (McBlock.parseMcGeneric, True, True, False, ),
2903 'IEM_MC_FETCH_MEM_I64': (McBlock.parseMcGeneric, True, True, False, ),
2904 'IEM_MC_FETCH_MEM_R32': (McBlock.parseMcGeneric, True, True, False, ),
2905 'IEM_MC_FETCH_MEM_R64': (McBlock.parseMcGeneric, True, True, False, ),
2906 'IEM_MC_FETCH_MEM_R80': (McBlock.parseMcGeneric, True, True, False, ),
2907 'IEM_MC_FETCH_MEM_U128': (McBlock.parseMcGeneric, True, True, False, ),
2908 'IEM_MC_FETCH_MEM_U128_ALIGN_SSE': (McBlock.parseMcGeneric, True, True, False, ),
2909 'IEM_MC_FETCH_MEM_U128_NO_AC': (McBlock.parseMcGeneric, True, True, False, ),
2910 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128': (McBlock.parseMcGeneric, True, True, False, ),
2911 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_RAX_RDX_U64': (McBlock.parseMcGeneric, True, True, False, ),
2912 'IEM_MC_FETCH_MEM_U128_AND_XREG_U128_AND_EAX_EDX_U32_SX_U64':(McBlock.parseMcGeneric, True, True, False, ),
2913 'IEM_MC_FETCH_MEM_U16': (McBlock.parseMcGeneric, True, True, True, ),
2914 'IEM_MC_FETCH_MEM_U16_DISP': (McBlock.parseMcGeneric, True, True, True, ),
2915 'IEM_MC_FETCH_MEM_U16_SX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movsx
2916 'IEM_MC_FETCH_MEM_U16_SX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movsx
2917 'IEM_MC_FETCH_MEM_U16_ZX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movzx
2918 'IEM_MC_FETCH_MEM_U16_ZX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movzx
2919 'IEM_MC_FETCH_MEM_U256': (McBlock.parseMcGeneric, True, True, False, ),
2920 'IEM_MC_FETCH_MEM_U256_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, False, ),
2921 'IEM_MC_FETCH_MEM_U256_NO_AC': (McBlock.parseMcGeneric, True, True, False, ),
2922 'IEM_MC_FETCH_MEM_U32': (McBlock.parseMcGeneric, True, True, True, ),
2923 'IEM_MC_FETCH_MEM_U32_DISP': (McBlock.parseMcGeneric, True, True, True, ), #bounds only
2924 'IEM_MC_FETCH_MEM_U32_SX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movsx
2925 'IEM_MC_FETCH_MEM_U32_ZX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movzx
2926 'IEM_MC_FETCH_MEM_U64': (McBlock.parseMcGeneric, True, True, True, ),
2927 'IEM_MC_FETCH_MEM_U64_ALIGN_U128': (McBlock.parseMcGeneric, True, True, False, ),
2928 'IEM_MC_FETCH_MEM_U8': (McBlock.parseMcGeneric, True, True, True, ),
2929 'IEM_MC_FETCH_MEM_U8_SX_U16': (McBlock.parseMcGeneric, True, True, True, ), # movsx
2930 'IEM_MC_FETCH_MEM_U8_SX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movsx
2931 'IEM_MC_FETCH_MEM_U8_SX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movsx
2932 'IEM_MC_FETCH_MEM_U8_ZX_U16': (McBlock.parseMcGeneric, True, True, True, ), # movzx
2933 'IEM_MC_FETCH_MEM_U8_ZX_U32': (McBlock.parseMcGeneric, True, True, True, ), # movzx
2934 'IEM_MC_FETCH_MEM_U8_ZX_U64': (McBlock.parseMcGeneric, True, True, True, ), # movzx
2935 'IEM_MC_FETCH_MEM_XMM': (McBlock.parseMcGeneric, True, True, False, ),
2936 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE': (McBlock.parseMcGeneric, True, True, False, ),
2937 'IEM_MC_FETCH_MEM_XMM_NO_AC': (McBlock.parseMcGeneric, True, True, False, ),
2938 'IEM_MC_FETCH_MEM_XMM_U32': (McBlock.parseMcGeneric, True, True, False, ),
2939 'IEM_MC_FETCH_MEM_XMM_U64': (McBlock.parseMcGeneric, True, True, False, ),
2940 'IEM_MC_FETCH_MEM_XMM_ALIGN_SSE_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
2941 'IEM_MC_FETCH_MEM_XMM_U32_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
2942 'IEM_MC_FETCH_MEM_XMM_U64_AND_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
2943 'IEM_MC_FETCH_MEM_YMM': (McBlock.parseMcGeneric, True, True, False, ),
2944 'IEM_MC_FETCH_MEM_YMM_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, False, ),
2945 'IEM_MC_FETCH_MEM_YMM_NO_AC': (McBlock.parseMcGeneric, True, True, False, ),
2946 'IEM_MC_FETCH_MEM16_U8': (McBlock.parseMcGeneric, True, True, False, ),
2947 'IEM_MC_FETCH_MEM32_U8': (McBlock.parseMcGeneric, True, True, False, ),
2948 'IEM_MC_FETCH_MREG_U32': (McBlock.parseMcGeneric, False, False, False, ),
2949 'IEM_MC_FETCH_MREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
2950 'IEM_MC_FETCH_SREG_BASE_U32': (McBlock.parseMcGeneric, False, False, False, ),
2951 'IEM_MC_FETCH_SREG_BASE_U64': (McBlock.parseMcGeneric, False, False, False, ),
2952 'IEM_MC_FETCH_SREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
2953 'IEM_MC_FETCH_SREG_ZX_U32': (McBlock.parseMcGeneric, False, False, True, ),
2954 'IEM_MC_FETCH_SREG_ZX_U64': (McBlock.parseMcGeneric, False, False, True, ),
2955 'IEM_MC_FETCH_XREG_U128': (McBlock.parseMcGeneric, False, False, False, ),
2956 'IEM_MC_FETCH_XREG_U16': (McBlock.parseMcGeneric, False, False, False, ),
2957 'IEM_MC_FETCH_XREG_U32': (McBlock.parseMcGeneric, False, False, False, ),
2958 'IEM_MC_FETCH_XREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
2959 'IEM_MC_FETCH_XREG_U8': (McBlock.parseMcGeneric, False, False, False, ),
2960 'IEM_MC_FETCH_XREG_XMM': (McBlock.parseMcGeneric, False, False, False, ),
2961 'IEM_MC_FETCH_XREG_PAIR_U128': (McBlock.parseMcGeneric, False, False, False, ),
2962 'IEM_MC_FETCH_XREG_PAIR_U128_AND_RAX_RDX_U64': (McBlock.parseMcGeneric, False, False, False, ),
2963 'IEM_MC_FETCH_XREG_PAIR_U128_AND_EAX_EDX_U32_SX_U64': (McBlock.parseMcGeneric, False, False, False, ),
2964 'IEM_MC_FETCH_XREG_PAIR_XMM': (McBlock.parseMcGeneric, False, False, False, ),
2965 'IEM_MC_FETCH_YREG_2ND_U64': (McBlock.parseMcGeneric, False, False, False, ),
2966 'IEM_MC_FETCH_YREG_U128': (McBlock.parseMcGeneric, False, False, False, ),
2967 'IEM_MC_FETCH_YREG_U256': (McBlock.parseMcGeneric, False, False, False, ),
2968 'IEM_MC_FETCH_YREG_U32': (McBlock.parseMcGeneric, False, False, False, ),
2969 'IEM_MC_FETCH_YREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
2970 'IEM_MC_FLIP_EFL_BIT': (McBlock.parseMcGeneric, True, True, False, ),
2971 'IEM_MC_FPU_FROM_MMX_MODE': (McBlock.parseMcGeneric, True, True, False, ),
2972 'IEM_MC_FPU_STACK_DEC_TOP': (McBlock.parseMcGeneric, True, True, False, ),
2973 'IEM_MC_FPU_STACK_FREE': (McBlock.parseMcGeneric, True, True, False, ),
2974 'IEM_MC_FPU_STACK_INC_TOP': (McBlock.parseMcGeneric, True, True, False, ),
2975 'IEM_MC_FPU_STACK_PUSH_OVERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
2976 'IEM_MC_FPU_STACK_PUSH_OVERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
2977 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
2978 'IEM_MC_FPU_STACK_PUSH_UNDERFLOW_TWO': (McBlock.parseMcGeneric, True, True, False, ),
2979 'IEM_MC_FPU_STACK_UNDERFLOW': (McBlock.parseMcGeneric, True, True, False, ),
2980 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
2981 'IEM_MC_FPU_STACK_UNDERFLOW_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
2982 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
2983 'IEM_MC_FPU_STACK_UNDERFLOW_THEN_POP_POP': (McBlock.parseMcGeneric, True, True, False, ),
2984 'IEM_MC_FPU_TO_MMX_MODE': (McBlock.parseMcGeneric, True, True, False, ),
2985 'IEM_MC_HINT_FLUSH_GUEST_SHADOW': (McBlock.parseMcGeneric, True, True, True, ),
2986 'IEM_MC_IF_CX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
2987 'IEM_MC_IF_CX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
2988 'IEM_MC_IF_CX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
2989 'IEM_MC_IF_CX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
2990 'IEM_MC_IF_ECX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
2991 'IEM_MC_IF_ECX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
2992 'IEM_MC_IF_ECX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
2993 'IEM_MC_IF_ECX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
2994 'IEM_MC_IF_EFL_ANY_BITS_SET': (McBlock.parseMcGenericCond, True, False, True, ),
2995 'IEM_MC_IF_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
2996 'IEM_MC_IF_EFL_BIT_NOT_SET_AND_BITS_EQ': (McBlock.parseMcGenericCond, True, False, True, ),
2997 'IEM_MC_IF_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
2998 'IEM_MC_IF_EFL_BIT_SET_OR_BITS_NE': (McBlock.parseMcGenericCond, True, False, True, ),
2999 'IEM_MC_IF_EFL_BITS_EQ': (McBlock.parseMcGenericCond, True, False, True, ),
3000 'IEM_MC_IF_EFL_BITS_NE': (McBlock.parseMcGenericCond, True, False, True, ),
3001 'IEM_MC_IF_EFL_NO_BITS_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3002 'IEM_MC_IF_FCW_IM': (McBlock.parseMcGenericCond, True, True, False, ),
3003 'IEM_MC_IF_FPUREG_IS_EMPTY': (McBlock.parseMcGenericCond, True, True, False, ),
3004 'IEM_MC_IF_FPUREG_NOT_EMPTY': (McBlock.parseMcGenericCond, True, True, False, ),
3005 'IEM_MC_IF_FPUREG_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, True, False, ),
3006 'IEM_MC_IF_GREG_BIT_SET': (McBlock.parseMcGenericCond, True, False, False, ),
3007 'IEM_MC_IF_LOCAL_IS_Z': (McBlock.parseMcGenericCond, True, False, False, ),
3008 'IEM_MC_IF_MXCSR_XCPT_PENDING': (McBlock.parseMcGenericCond, True, True, False, ),
3009 'IEM_MC_IF_RCX_IS_NZ': (McBlock.parseMcGenericCond, True, False, True, ),
3010 'IEM_MC_IF_RCX_IS_NOT_ONE': (McBlock.parseMcGenericCond, True, False, True, ),
3011 'IEM_MC_IF_RCX_IS_NOT_ONE_AND_EFL_BIT_NOT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3012 'IEM_MC_IF_RCX_IS_NOT_ONE_AND_EFL_BIT_SET': (McBlock.parseMcGenericCond, True, False, True, ),
3013 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80': (McBlock.parseMcGenericCond, True, True, False, ),
3014 'IEM_MC_IF_TWO_FPUREGS_NOT_EMPTY_REF_R80_FIRST': (McBlock.parseMcGenericCond, True, True, False, ),
3015 'IEM_MC_IMPLICIT_AVX_AIMPL_ARGS': (McBlock.parseMcImplicitAvxAArgs, False, False, False, ),
3016 'IEM_MC_INT_CLEAR_ZMM_256_UP': (McBlock.parseMcGeneric, True, True, False, ),
3017 'IEM_MC_LOCAL': (McBlock.parseMcLocal, False, False, True, ),
3018 'IEM_MC_LOCAL_ASSIGN': (McBlock.parseMcLocalAssign, False, False, True, ),
3019 'IEM_MC_LOCAL_CONST': (McBlock.parseMcLocalConst, False, False, True, ),
3020 'IEM_MC_MAYBE_RAISE_AVX_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3021 'IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, True, False, ),
3022 'IEM_MC_MAYBE_RAISE_FPU_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3023 'IEM_MC_MAYBE_RAISE_FSGSBASE_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3024 'IEM_MC_MAYBE_RAISE_MMX_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3025 'IEM_MC_MAYBE_RAISE_NON_CANONICAL_ADDR_GP0': (McBlock.parseMcGeneric, True, True, False, ),
3026 'IEM_MC_MAYBE_RAISE_SSE_AVX_SIMD_FP_OR_UD_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3027 'IEM_MC_MAYBE_RAISE_SSE_RELATED_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3028 'IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE': (McBlock.parseMcGeneric, True, True, False, ),
3029 'IEM_MC_MEM_COMMIT_AND_UNMAP_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3030 'IEM_MC_MEM_COMMIT_AND_UNMAP_RW': (McBlock.parseMcGeneric, True, True, True, ),
3031 'IEM_MC_MEM_COMMIT_AND_UNMAP_RO': (McBlock.parseMcGeneric, True, True, True, ),
3032 'IEM_MC_MEM_COMMIT_AND_UNMAP_WO': (McBlock.parseMcGeneric, True, True, True, ),
3033 'IEM_MC_MEM_COMMIT_AND_UNMAP_FOR_FPU_STORE_WO': (McBlock.parseMcGeneric, True, True, False, ),
3034 'IEM_MC_MEM_MAP_D80_WO': (McBlock.parseMcGeneric, True, True, True, ),
3035 'IEM_MC_MEM_MAP_I16_WO': (McBlock.parseMcGeneric, True, True, True, ),
3036 'IEM_MC_MEM_MAP_I32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3037 'IEM_MC_MEM_MAP_I64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3038 'IEM_MC_MEM_MAP_R32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3039 'IEM_MC_MEM_MAP_R64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3040 'IEM_MC_MEM_MAP_R80_WO': (McBlock.parseMcGeneric, True, True, True, ),
3041 'IEM_MC_MEM_MAP_U8_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3042 'IEM_MC_MEM_MAP_U8_RW': (McBlock.parseMcGeneric, True, True, True, ),
3043 'IEM_MC_MEM_MAP_U8_RO': (McBlock.parseMcGeneric, True, True, True, ),
3044 'IEM_MC_MEM_MAP_U8_WO': (McBlock.parseMcGeneric, True, True, True, ),
3045 'IEM_MC_MEM_MAP_U16_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3046 'IEM_MC_MEM_MAP_U16_RW': (McBlock.parseMcGeneric, True, True, True, ),
3047 'IEM_MC_MEM_MAP_U16_RO': (McBlock.parseMcGeneric, True, True, True, ),
3048 'IEM_MC_MEM_MAP_U16_WO': (McBlock.parseMcGeneric, True, True, True, ),
3049 'IEM_MC_MEM_MAP_U32_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3050 'IEM_MC_MEM_MAP_U32_RW': (McBlock.parseMcGeneric, True, True, True, ),
3051 'IEM_MC_MEM_MAP_U32_RO': (McBlock.parseMcGeneric, True, True, True, ),
3052 'IEM_MC_MEM_MAP_U32_WO': (McBlock.parseMcGeneric, True, True, True, ),
3053 'IEM_MC_MEM_MAP_U64_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3054 'IEM_MC_MEM_MAP_U64_RW': (McBlock.parseMcGeneric, True, True, True, ),
3055 'IEM_MC_MEM_MAP_U64_RO': (McBlock.parseMcGeneric, True, True, True, ),
3056 'IEM_MC_MEM_MAP_U64_WO': (McBlock.parseMcGeneric, True, True, True, ),
3057 'IEM_MC_MEM_MAP_U128_ATOMIC': (McBlock.parseMcGeneric, True, True, True, ),
3058 'IEM_MC_MEM_MAP_U128_RW': (McBlock.parseMcGeneric, True, True, True, ),
3059 'IEM_MC_MEM_MAP_U128_RO': (McBlock.parseMcGeneric, True, True, True, ),
3060 'IEM_MC_MEM_MAP_U128_WO': (McBlock.parseMcGeneric, True, True, True, ),
3061 'IEM_MC_MEM_ROLLBACK_AND_UNMAP_WO': (McBlock.parseMcGeneric, True, True, True, ),
3062 'IEM_MC_MERGE_YREG_U32_U96_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3063 'IEM_MC_MERGE_YREG_U64_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3064 'IEM_MC_MERGE_YREG_U64HI_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3065 'IEM_MC_MERGE_YREG_U64LO_U64LO_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3066 'IEM_MC_MERGE_YREG_U64LO_U64LOCAL_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3067 'IEM_MC_MERGE_YREG_U64LOCAL_U64HI_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3068 'IEM_MC_MODIFIED_MREG': (McBlock.parseMcGeneric, True, True, False, ),
3069 'IEM_MC_MODIFIED_MREG_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3070 'IEM_MC_OR_2LOCS_U32': (McBlock.parseMcGeneric, False, False, False, ),
3071 'IEM_MC_OR_GREG_U16': (McBlock.parseMcGeneric, True, True, False, ),
3072 'IEM_MC_OR_GREG_U32': (McBlock.parseMcGeneric, True, True, False, ),
3073 'IEM_MC_OR_GREG_U64': (McBlock.parseMcGeneric, True, True, False, ),
3074 'IEM_MC_OR_GREG_U8': (McBlock.parseMcGeneric, True, True, False, ),
3075 'IEM_MC_OR_LOCAL_U16': (McBlock.parseMcGeneric, False, False, False, ),
3076 'IEM_MC_OR_LOCAL_U32': (McBlock.parseMcGeneric, False, False, False, ),
3077 'IEM_MC_OR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, False, ),
3078 'IEM_MC_POP_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3079 'IEM_MC_POP_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3080 'IEM_MC_POP_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3081 'IEM_MC_PREPARE_AVX_USAGE': (McBlock.parseMcGeneric, False, False, True),
3082 'IEM_MC_PREPARE_FPU_USAGE': (McBlock.parseMcGeneric, False, False, True),
3083 'IEM_MC_PREPARE_SSE_USAGE': (McBlock.parseMcGeneric, False, False, True),
3084 'IEM_MC_PUSH_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3085 'IEM_MC_PUSH_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3086 'IEM_MC_PUSH_FPU_RESULT_TWO': (McBlock.parseMcGeneric, True, True, False, ),
3087 'IEM_MC_PUSH_U16': (McBlock.parseMcGeneric, True, True, True, ),
3088 'IEM_MC_PUSH_U32': (McBlock.parseMcGeneric, True, True, True, ),
3089 'IEM_MC_PUSH_U32_SREG': (McBlock.parseMcGeneric, True, True, True, ),
3090 'IEM_MC_PUSH_U64': (McBlock.parseMcGeneric, True, True, True, ),
3091 'IEM_MC_RAISE_DIVIDE_ERROR': (McBlock.parseMcGeneric, True, True, False, ),
3092 'IEM_MC_RAISE_GP0_IF_CPL_NOT_ZERO': (McBlock.parseMcGeneric, True, True, False, ),
3093 'IEM_MC_RAISE_GP0_IF_EFF_ADDR_UNALIGNED': (McBlock.parseMcGeneric, True, True, False, ),
3094 'IEM_MC_RAISE_SSE_AVX_SIMD_FP_OR_UD_XCPT': (McBlock.parseMcGeneric, True, True, False, ),
3095 'IEM_MC_REF_EFLAGS': (McBlock.parseMcGeneric, False, False, True, ),
3096 'IEM_MC_REF_FPUREG': (McBlock.parseMcGeneric, False, False, False, ),
3097 'IEM_MC_REF_GREG_I32': (McBlock.parseMcGeneric, False, False, True, ),
3098 'IEM_MC_REF_GREG_I32_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3099 'IEM_MC_REF_GREG_I64': (McBlock.parseMcGeneric, False, False, True, ),
3100 'IEM_MC_REF_GREG_I64_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3101 'IEM_MC_REF_GREG_U16': (McBlock.parseMcGeneric, False, False, True, ),
3102 'IEM_MC_REF_GREG_U16_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3103 'IEM_MC_REF_GREG_U32': (McBlock.parseMcGeneric, False, False, True, ),
3104 'IEM_MC_REF_GREG_U32_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3105 'IEM_MC_REF_GREG_U64': (McBlock.parseMcGeneric, False, False, True, ),
3106 'IEM_MC_REF_GREG_U64_CONST': (McBlock.parseMcGeneric, False, False, True, ),
3107 'IEM_MC_REF_GREG_U8': (McBlock.parseMcGeneric, False, False, False, ), # threaded
3108 'IEM_MC_REF_GREG_U8_CONST': (McBlock.parseMcGeneric, False, False, False, ), # threaded
3109 'IEM_MC_REF_LOCAL': (McBlock.parseMcGeneric, False, False, False, ), # eliminate!
3110 'IEM_MC_REF_MREG_U32_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3111 'IEM_MC_REF_MREG_U64': (McBlock.parseMcGeneric, False, False, False, ),
3112 'IEM_MC_REF_MREG_U64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3113 'IEM_MC_REF_MXCSR': (McBlock.parseMcGeneric, False, False, False, ),
3114 'IEM_MC_REF_XREG_R32_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3115 'IEM_MC_REF_XREG_R64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3116 'IEM_MC_REF_XREG_U128': (McBlock.parseMcGeneric, False, False, False, ),
3117 'IEM_MC_REF_XREG_U128_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3118 'IEM_MC_REF_XREG_U32_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3119 'IEM_MC_REF_XREG_U64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3120 'IEM_MC_REF_XREG_XMM_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3121 'IEM_MC_REF_YREG_U128': (McBlock.parseMcGeneric, False, False, False, ),
3122 'IEM_MC_REF_YREG_U128_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3123 'IEM_MC_REF_YREG_U64_CONST': (McBlock.parseMcGeneric, False, False, False, ),
3124 'IEM_MC_REL_JMP_S16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3125 'IEM_MC_REL_JMP_S32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3126 'IEM_MC_REL_JMP_S8_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3127 'IEM_MC_RETURN_ON_FAILURE': (McBlock.parseMcGeneric, False, False, False, ),
3128 'IEM_MC_SAR_LOCAL_S16': (McBlock.parseMcGeneric, False, False, False, ),
3129 'IEM_MC_SAR_LOCAL_S32': (McBlock.parseMcGeneric, False, False, False, ),
3130 'IEM_MC_SAR_LOCAL_S64': (McBlock.parseMcGeneric, False, False, False, ),
3131 'IEM_MC_SET_EFL_BIT': (McBlock.parseMcGeneric, True, True, False, ),
3132 'IEM_MC_SET_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3133 'IEM_MC_SET_RIP_U16_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3134 'IEM_MC_SET_RIP_U32_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3135 'IEM_MC_SET_RIP_U64_AND_FINISH': (McBlock.parseMcGeneric, True, True, False, ),
3136 'IEM_MC_SHL_LOCAL_S16': (McBlock.parseMcGeneric, False, False, False, ),
3137 'IEM_MC_SHL_LOCAL_S32': (McBlock.parseMcGeneric, False, False, False, ),
3138 'IEM_MC_SHL_LOCAL_S64': (McBlock.parseMcGeneric, False, False, False, ),
3139 'IEM_MC_SHR_LOCAL_U8': (McBlock.parseMcGeneric, False, False, False, ),
3140 'IEM_MC_SSE_UPDATE_MXCSR': (McBlock.parseMcGeneric, True, True, False, ),
3141 'IEM_MC_STORE_FPU_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3142 'IEM_MC_STORE_FPU_RESULT_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3143 'IEM_MC_STORE_FPU_RESULT_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3144 'IEM_MC_STORE_FPU_RESULT_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3145 'IEM_MC_STORE_FPUREG_R80_SRC_REF': (McBlock.parseMcGeneric, True, True, False, ),
3146 'IEM_MC_STORE_GREG_I64': (McBlock.parseMcGeneric, True, True, False, ),
3147 'IEM_MC_STORE_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3148 'IEM_MC_STORE_GREG_U16_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3149 'IEM_MC_STORE_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3150 'IEM_MC_STORE_GREG_U32_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3151 'IEM_MC_STORE_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3152 'IEM_MC_STORE_GREG_U64_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3153 'IEM_MC_STORE_GREG_U8': (McBlock.parseMcGeneric, True, True, True, ), # thrd var
3154 'IEM_MC_STORE_GREG_U8_CONST': (McBlock.parseMcGeneric, True, True, True, ), # thrd var
3155 'IEM_MC_STORE_GREG_PAIR_U32': (McBlock.parseMcGeneric, True, True, False, ),
3156 'IEM_MC_STORE_GREG_PAIR_U64': (McBlock.parseMcGeneric, True, True, False, ),
3157 'IEM_MC_STORE_MEM_I16_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3158 'IEM_MC_STORE_MEM_I32_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3159 'IEM_MC_STORE_MEM_I64_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3160 'IEM_MC_STORE_MEM_I8_CONST_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3161 'IEM_MC_STORE_MEM_INDEF_D80_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3162 'IEM_MC_STORE_MEM_NEG_QNAN_R32_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3163 'IEM_MC_STORE_MEM_NEG_QNAN_R64_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3164 'IEM_MC_STORE_MEM_NEG_QNAN_R80_BY_REF': (McBlock.parseMcGeneric, True, True, False, ),
3165 'IEM_MC_STORE_MEM_U128': (McBlock.parseMcGeneric, True, True, False, ),
3166 'IEM_MC_STORE_MEM_U128_ALIGN_SSE': (McBlock.parseMcGeneric, True, True, False, ),
3167 'IEM_MC_STORE_MEM_U16': (McBlock.parseMcGeneric, True, True, True, ),
3168 'IEM_MC_STORE_MEM_U16_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3169 'IEM_MC_STORE_MEM_U256': (McBlock.parseMcGeneric, True, True, False, ),
3170 'IEM_MC_STORE_MEM_U256_ALIGN_AVX': (McBlock.parseMcGeneric, True, True, False, ),
3171 'IEM_MC_STORE_MEM_U32': (McBlock.parseMcGeneric, True, True, True, ),
3172 'IEM_MC_STORE_MEM_U32_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3173 'IEM_MC_STORE_MEM_U64': (McBlock.parseMcGeneric, True, True, True, ),
3174 'IEM_MC_STORE_MEM_U64_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3175 'IEM_MC_STORE_MEM_U8': (McBlock.parseMcGeneric, True, True, True, ),
3176 'IEM_MC_STORE_MEM_U8_CONST': (McBlock.parseMcGeneric, True, True, True, ),
3177 'IEM_MC_STORE_MREG_U32_ZX_U64': (McBlock.parseMcGeneric, True, True, False, ),
3178 'IEM_MC_STORE_MREG_U64': (McBlock.parseMcGeneric, True, True, False, ),
3179 'IEM_MC_STORE_SREG_BASE_U32': (McBlock.parseMcGeneric, True, True, False, ),
3180 'IEM_MC_STORE_SREG_BASE_U64': (McBlock.parseMcGeneric, True, True, False, ),
3181 'IEM_MC_STORE_SSE_RESULT': (McBlock.parseMcGeneric, True, True, False, ),
3182 'IEM_MC_STORE_XREG_HI_U64': (McBlock.parseMcGeneric, True, True, False, ),
3183 'IEM_MC_STORE_XREG_R32': (McBlock.parseMcGeneric, True, True, False, ),
3184 'IEM_MC_STORE_XREG_R64': (McBlock.parseMcGeneric, True, True, False, ),
3185 'IEM_MC_STORE_XREG_U128': (McBlock.parseMcGeneric, True, True, False, ),
3186 'IEM_MC_STORE_XREG_U16': (McBlock.parseMcGeneric, True, True, False, ),
3187 'IEM_MC_STORE_XREG_U32': (McBlock.parseMcGeneric, True, True, False, ),
3188 'IEM_MC_STORE_XREG_U32_U128': (McBlock.parseMcGeneric, True, True, False, ),
3189 'IEM_MC_STORE_XREG_U32_ZX_U128': (McBlock.parseMcGeneric, True, True, False, ),
3190 'IEM_MC_STORE_XREG_U64': (McBlock.parseMcGeneric, True, True, False, ),
3191 'IEM_MC_STORE_XREG_U64_ZX_U128': (McBlock.parseMcGeneric, True, True, False, ),
3192 'IEM_MC_STORE_XREG_U8': (McBlock.parseMcGeneric, True, True, False, ),
3193 'IEM_MC_STORE_XREG_XMM': (McBlock.parseMcGeneric, True, True, False, ),
3194 'IEM_MC_STORE_XREG_XMM_U32': (McBlock.parseMcGeneric, True, True, False, ),
3195 'IEM_MC_STORE_XREG_XMM_U64': (McBlock.parseMcGeneric, True, True, False, ),
3196 'IEM_MC_STORE_YREG_U128': (McBlock.parseMcGeneric, True, True, False, ),
3197 'IEM_MC_STORE_YREG_U128_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3198 'IEM_MC_STORE_YREG_U256_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3199 'IEM_MC_STORE_YREG_U32_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3200 'IEM_MC_STORE_YREG_U64_ZX_VLMAX': (McBlock.parseMcGeneric, True, True, False, ),
3201 'IEM_MC_SUB_GREG_U16': (McBlock.parseMcGeneric, True, True, True, ),
3202 'IEM_MC_SUB_GREG_U32': (McBlock.parseMcGeneric, True, True, True, ),
3203 'IEM_MC_SUB_GREG_U64': (McBlock.parseMcGeneric, True, True, True, ),
3204 'IEM_MC_SUB_LOCAL_U16': (McBlock.parseMcGeneric, False, False, False, ),
3205 'IEM_MC_UPDATE_FPU_OPCODE_IP': (McBlock.parseMcGeneric, True, True, False, ),
3206 'IEM_MC_UPDATE_FSW': (McBlock.parseMcGeneric, True, True, False, ),
3207 'IEM_MC_UPDATE_FSW_CONST': (McBlock.parseMcGeneric, True, True, False, ),
3208 'IEM_MC_UPDATE_FSW_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3209 'IEM_MC_UPDATE_FSW_THEN_POP_POP': (McBlock.parseMcGeneric, True, True, False, ),
3210 'IEM_MC_UPDATE_FSW_WITH_MEM_OP': (McBlock.parseMcGeneric, True, True, False, ),
3211 'IEM_MC_UPDATE_FSW_WITH_MEM_OP_THEN_POP': (McBlock.parseMcGeneric, True, True, False, ),
3212 'IEM_MC_NO_NATIVE_RECOMPILE': (McBlock.parseMcGeneric, False, False, False, ),
3213};
3214# pylint: enable=line-too-long
3215
3216## List of microcode blocks.
3217g_aoMcBlocks = [] # type: List[McBlock]
3218
3219
3220
3221class ParserException(Exception):
3222 """ Parser exception """
3223 def __init__(self, sMessage):
3224 Exception.__init__(self, sMessage);
3225
3226
3227class SimpleParser(object): # pylint: disable=too-many-instance-attributes
3228 """
3229 Parser of IEMAllInstruction*.cpp.h instruction specifications.
3230 """
3231
3232 ## @name Parser state.
3233 ## @{
3234 kiCode = 0;
3235 kiCommentMulti = 1;
3236 ## @}
3237
3238 class Macro(object):
3239 """ Macro """
3240 def __init__(self, sName, asArgs, sBody, iLine):
3241 self.sName = sName; ##< The macro name.
3242 self.asArgs = asArgs; ##< None if simple macro, list of parameters otherwise.
3243 self.sBody = sBody;
3244 self.iLine = iLine;
3245 self.oReArgMatch = re.compile(r'(\s*##\s*|\b)(' + '|'.join(asArgs) + r')(\s*##\s*|\b)') if asArgs else None;
3246
3247 @staticmethod
3248 def _needSpace(ch):
3249 """ This is just to make the expanded output a bit prettier. """
3250 return ch.isspace() and ch != '(';
3251
3252 def expandMacro(self, oParent, asArgs = None):
3253 """ Expands the macro body with the given arguments. """
3254 _ = oParent;
3255 sBody = self.sBody;
3256
3257 if self.oReArgMatch:
3258 assert len(asArgs) == len(self.asArgs);
3259 #oParent.debug('%s: %s' % (self.sName, self.oReArgMatch.pattern,));
3260
3261 dArgs = { self.asArgs[iArg]: sValue for iArg, sValue in enumerate(asArgs) };
3262 oMatch = self.oReArgMatch.search(sBody);
3263 while oMatch:
3264 sName = oMatch.group(2);
3265 #oParent.debug('%s %s..%s (%s)' % (sName, oMatch.start(), oMatch.end(),oMatch.group()));
3266 sValue = dArgs[sName];
3267 sPre = '';
3268 if not oMatch.group(1) and oMatch.start() > 0 and self._needSpace(sBody[oMatch.start()]):
3269 sPre = ' ';
3270 sPost = '';
3271 if not oMatch.group(3) and oMatch.end() < len(sBody) and self._needSpace(sBody[oMatch.end()]):
3272 sPost = ' ';
3273 sBody = sBody[ : oMatch.start()] + sPre + sValue + sPost + sBody[oMatch.end() : ];
3274 oMatch = self.oReArgMatch.search(sBody, oMatch.start() + len(sValue));
3275 else:
3276 assert not asArgs;
3277
3278 return sBody;
3279
3280 class PreprocessorConditional(object):
3281 """ Preprocessor conditional (#if/#ifdef/#ifndef/#elif/#else/#endif). """
3282
3283 ## Known defines.
3284 # - A value of 1 indicates that it's always defined.
3285 # - A value of 0 if it's always undefined
3286 # - A value of -1 if it's an arch and it depends of script parameters.
3287 # - A value of -2 if it's not recognized when filtering MC blocks.
3288 kdKnownDefines = {
3289 'IEM_WITH_ONE_BYTE_TABLE': 1,
3290 'IEM_WITH_TWO_BYTE_TABLE': 1,
3291 'IEM_WITH_THREE_0F_38': 1,
3292 'IEM_WITH_THREE_0F_3A': 1,
3293 'IEM_WITH_THREE_BYTE_TABLES': 1,
3294 'IEM_WITH_3DNOW': 1,
3295 'IEM_WITH_3DNOW_TABLE': 1,
3296 'IEM_WITH_VEX': 1,
3297 'IEM_WITH_VEX_TABLES': 1,
3298 'VBOX_WITH_NESTED_HWVIRT_VMX': 1,
3299 'VBOX_WITH_NESTED_HWVIRT_VMX_EPT': 1,
3300 'VBOX_WITH_NESTED_HWVIRT_SVM': 1,
3301 'LOG_ENABLED': 1,
3302 'RT_WITHOUT_PRAGMA_ONCE': 0,
3303 'TST_IEM_CHECK_MC': 0,
3304 'IEM_WITHOUT_ASSEMBLY': -2, ##< @todo ??
3305 'RT_ARCH_AMD64': -1,
3306 'RT_ARCH_ARM64': -1,
3307 'RT_ARCH_ARM32': -1,
3308 'RT_ARCH_X86': -1,
3309 'RT_ARCH_SPARC': -1,
3310 'RT_ARCH_SPARC64': -1,
3311 };
3312 kdBuildArchToIprt = {
3313 'amd64': 'RT_ARCH_AMD64',
3314 'arm64': 'RT_ARCH_ARM64',
3315 'sparc32': 'RT_ARCH_SPARC64',
3316 };
3317 ## For parsing the next defined(xxxx).
3318 koMatchDefined = re.compile(r'\s*defined\s*\(\s*([^ \t)]+)\s*\)\s*');
3319
3320 def __init__(self, sType, sExpr):
3321 self.sType = sType;
3322 self.sExpr = sExpr; ##< Expression without command and no leading or trailing spaces.
3323 self.aoElif = [] # type: List[PreprocessorConditional]
3324 self.fInElse = [];
3325 if sType in ('if', 'elif'):
3326 self.checkExpression(sExpr);
3327 else:
3328 self.checkSupportedDefine(sExpr)
3329
3330 @staticmethod
3331 def checkSupportedDefine(sDefine):
3332 """ Checks that sDefine is one that we support. Raises exception if unuspported. """
3333 #print('debug: checkSupportedDefine: %s' % (sDefine,), file = sys.stderr);
3334 if sDefine in SimpleParser.PreprocessorConditional.kdKnownDefines:
3335 return True;
3336 if sDefine.startswith('VMM_INCLUDED_') and sDefine.endswith('_h'):
3337 return True;
3338 raise Exception('Unsupported define: %s' % (sDefine,));
3339
3340 @staticmethod
3341 def checkExpression(sExpr):
3342 """ Check that the expression is supported. Raises exception if not. """
3343 #print('debug: checkExpression: %s' % (sExpr,), file = sys.stderr);
3344 if sExpr in ('0', '1'):
3345 return True;
3346
3347 off = 0;
3348 cParan = 0;
3349 while off < len(sExpr):
3350 ch = sExpr[off];
3351
3352 # Unary operator or parentheses:
3353 if ch in ('(', '!'):
3354 if ch == '(':
3355 cParan += 1;
3356 off += 1;
3357 else:
3358 # defined(xxxx)
3359 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3360 if oMatch:
3361 SimpleParser.PreprocessorConditional.checkSupportedDefine(oMatch.group(1));
3362 elif sExpr[off:] != '1':
3363 raise Exception('Cannot grok: \'%s\' (at %u in: \'%s\')' % (sExpr[off:10], off + 1, sExpr,));
3364 off = oMatch.end();
3365
3366 # Look for closing parentheses.
3367 while off < len(sExpr) and sExpr[off].isspace():
3368 off += 1;
3369 if cParan > 0:
3370 while off < len(sExpr) and sExpr[off] == ')':
3371 if cParan <= 0:
3372 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3373 cParan -= 1;
3374 off += 1;
3375 while off < len(sExpr) and sExpr[off].isspace():
3376 off += 1;
3377
3378 # Look for binary operator.
3379 if off >= len(sExpr):
3380 break;
3381 if sExpr[off:off + 2] in ('||', '&&'):
3382 off += 2;
3383 else:
3384 raise Exception('Cannot grok operator: \'%s\' (at %u in: \'%s\')' % (sExpr[off:2], off + 1, sExpr,));
3385
3386 # Skip spaces.
3387 while off < len(sExpr) and sExpr[off].isspace():
3388 off += 1;
3389 if cParan != 0:
3390 raise Exception('Unbalanced parentheses at %u in \'%s\'' % (off + 1, sExpr,));
3391 return True;
3392
3393 @staticmethod
3394 def isArchIncludedInExpr(sExpr, sArch):
3395 """ Checks if sArch is included in the given expression. """
3396 # We only grok defined() [|| defined()...] and [1|0] at the moment.
3397 if sExpr == '0':
3398 return False;
3399 if sExpr == '1':
3400 return True;
3401 off = 0;
3402 while off < len(sExpr):
3403 # defined(xxxx)
3404 oMatch = SimpleParser.PreprocessorConditional.koMatchDefined.match(sExpr, off);
3405 if not oMatch:
3406 if sExpr[off:] == '1':
3407 return True;
3408 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3409 if SimpleParser.PreprocessorConditional.matchDefined(oMatch.group(1), sArch):
3410 return True;
3411 off = oMatch.end();
3412
3413 # Look for OR operator.
3414 while off + 1 < len(sExpr) and sExpr[off + 1].isspace():
3415 off += 1;
3416 if off >= len(sExpr):
3417 break;
3418 if sExpr.startswith('||'):
3419 off += 2;
3420 else:
3421 raise Exception('Cannot grok: %s (at %u in: %s)' % (sExpr[off:10], off + 1, sExpr,));
3422
3423 return False;
3424
3425 @staticmethod
3426 def matchArch(sDefine, sArch):
3427 """ Compares sDefine (RT_ARCH_XXXX) and sArch (x86, amd64, arm64, ++). """
3428 return SimpleParser.PreprocessorConditional.kdBuildArchToIprt[sArch] == sDefine;
3429
3430 @staticmethod
3431 def matchDefined(sExpr, sArch):
3432 """ Check the result of an ifdef/ifndef expression, given sArch. """
3433 iDefine = SimpleParser.PreprocessorConditional.kdKnownDefines.get(sExpr, 0);
3434 if iDefine == -2:
3435 raise Exception('Unsupported define for MC block filtering: %s' % (sExpr,));
3436 return iDefine == 1 or (iDefine == -1 and SimpleParser.PreprocessorConditional.matchArch(sExpr, sArch));
3437
3438 def isArchIncludedInPrimaryBlock(self, sArch):
3439 """ Checks if sArch is included in the (primary) 'if' block. """
3440 if self.sType == 'ifdef':
3441 return self.matchDefined(self.sExpr, sArch);
3442 if self.sType == 'ifndef':
3443 return not self.matchDefined(self.sExpr, sArch);
3444 return self.isArchIncludedInExpr(self.sExpr, sArch);
3445
3446 @staticmethod
3447 def isInBlockForArch(aoCppCondStack, sArch, iLine):
3448 """ Checks if sArch is included in the current conditional block. """
3449 _ = iLine;
3450 #print('debug: isInBlockForArch(%s,%s); line %s' % (len(aoCppCondStack), sArch, iLine), file = sys.stderr);
3451 for oCond in aoCppCondStack:
3452 if oCond.isArchIncludedInPrimaryBlock(sArch):
3453 if oCond.aoElif or oCond.fInElse:
3454 #print('debug: isInBlockForArch -> False #1', file = sys.stderr);
3455 return False;
3456 #print('debug: isInBlockForArch(%s,%s): in IF-block' % (len(aoCppCondStack), sArch), file = sys.stderr);
3457 else:
3458 fFine = False;
3459 for oElifCond in oCond.aoElif:
3460 if oElifCond.isArchIncludedInPrimaryBlock(sArch):
3461 if oElifCond is not oCond.aoElif[-1] or oCond.fInElse:
3462 #print('debug: isInBlockForArch -> False #3', file = sys.stderr);
3463 return False;
3464 fFine = True;
3465 if not fFine and not oCond.fInElse:
3466 #print('debug: isInBlockForArch -> False #4', file = sys.stderr);
3467 return False;
3468 #print('debug: isInBlockForArch -> True', file = sys.stderr);
3469 return True;
3470
3471 def __init__(self, sSrcFile, asLines, sDefaultMap, sHostArch, oInheritMacrosFrom = None):
3472 self.sSrcFile = sSrcFile;
3473 self.asLines = asLines;
3474 self.iLine = 0;
3475 self.iState = self.kiCode;
3476 self.sComment = '';
3477 self.iCommentLine = 0;
3478 self.aoCurInstrs = [] # type: List[Instruction]
3479 self.oCurFunction = None # type: DecoderFunction
3480 self.iMcBlockInFunc = 0;
3481 self.oCurMcBlock = None # type: McBlock
3482 self.dMacros = {} # type: Dict[str, SimpleParser.Macro]
3483 self.oReMacros = None # type: re ##< Regular expression matching invocations of anything in self.dMacros.
3484 if oInheritMacrosFrom:
3485 self.dMacros = dict(oInheritMacrosFrom.dMacros);
3486 self.oReMacros = oInheritMacrosFrom.oReMacros;
3487 self.aoCppCondStack = [] # type: List[PreprocessorConditional] ##< Preprocessor conditional stack.
3488 self.sHostArch = sHostArch;
3489
3490 assert sDefaultMap in g_dInstructionMaps;
3491 self.oDefaultMap = g_dInstructionMaps[sDefaultMap];
3492
3493 self.cTotalInstr = 0;
3494 self.cTotalStubs = 0;
3495 self.cTotalTagged = 0;
3496 self.cTotalMcBlocks = 0;
3497
3498 self.oReMacroName = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3499 self.oReMnemonic = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3500 self.oReStatsName = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*$');
3501 self.oReFunctionName= re.compile(r'^iemOp_[A-Za-z_][A-Za-z0-9_]*$');
3502 self.oReGroupName = re.compile(r'^og_[a-z0-9]+(|_[a-z0-9]+|_[a-z0-9]+_[a-z0-9]+)$');
3503 self.oReDisEnum = re.compile(r'^OP_[A-Z0-9_]+$');
3504 self.oReFunTable = re.compile(r'^(IEM_STATIC|static) +const +PFNIEMOP +g_apfn[A-Za-z0-9_]+ *\[ *\d* *\] *= *$');
3505 self.oReComment = re.compile(r'//.*?$|/\*.*?\*/'); ## Full comments.
3506 self.oReHashDefine2 = re.compile(r'(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)\(([^)]*)\)\s*(.*)\Z'); ##< With arguments.
3507 self.oReHashDefine3 = re.compile(r'(?s)\A\s*([A-Za-z_][A-Za-z0-9_]*)[^(]\s*(.*)\Z'); ##< Simple, no arguments.
3508 self.oReMcBeginEnd = re.compile(r'\bIEM_MC_(BEGIN|END|DEFER_TO_CIMPL_[1-5]_RET)\s*\('); ##> Not DEFER_TO_CIMPL_0_RET!
3509 self.fDebug = True;
3510 self.fDebugMc = False;
3511 self.fDebugPreproc = False;
3512
3513 self.dTagHandlers = {
3514 '@opbrief': self.parseTagOpBrief,
3515 '@opdesc': self.parseTagOpDesc,
3516 '@opmnemonic': self.parseTagOpMnemonic,
3517 '@op1': self.parseTagOpOperandN,
3518 '@op2': self.parseTagOpOperandN,
3519 '@op3': self.parseTagOpOperandN,
3520 '@op4': self.parseTagOpOperandN,
3521 '@oppfx': self.parseTagOpPfx,
3522 '@opmaps': self.parseTagOpMaps,
3523 '@opcode': self.parseTagOpcode,
3524 '@opcodesub': self.parseTagOpcodeSub,
3525 '@openc': self.parseTagOpEnc,
3526 '@opfltest': self.parseTagOpEFlags,
3527 '@opflmodify': self.parseTagOpEFlags,
3528 '@opflundef': self.parseTagOpEFlags,
3529 '@opflset': self.parseTagOpEFlags,
3530 '@opflclear': self.parseTagOpEFlags,
3531 '@ophints': self.parseTagOpHints,
3532 '@opdisenum': self.parseTagOpDisEnum,
3533 '@opmincpu': self.parseTagOpMinCpu,
3534 '@opcpuid': self.parseTagOpCpuId,
3535 '@opgroup': self.parseTagOpGroup,
3536 '@opunused': self.parseTagOpUnusedInvalid,
3537 '@opinvalid': self.parseTagOpUnusedInvalid,
3538 '@opinvlstyle': self.parseTagOpUnusedInvalid,
3539 '@optest': self.parseTagOpTest,
3540 '@optestign': self.parseTagOpTestIgnore,
3541 '@optestignore': self.parseTagOpTestIgnore,
3542 '@opcopytests': self.parseTagOpCopyTests,
3543 '@oponly': self.parseTagOpOnlyTest,
3544 '@oponlytest': self.parseTagOpOnlyTest,
3545 '@opxcpttype': self.parseTagOpXcptType,
3546 '@opstats': self.parseTagOpStats,
3547 '@opfunction': self.parseTagOpFunction,
3548 '@opdone': self.parseTagOpDone,
3549 };
3550 for i in range(48):
3551 self.dTagHandlers['@optest%u' % (i,)] = self.parseTagOpTestNum;
3552 self.dTagHandlers['@optest[%u]' % (i,)] = self.parseTagOpTestNum;
3553
3554 self.asErrors = [];
3555
3556 def raiseError(self, sMessage):
3557 """
3558 Raise error prefixed with the source and line number.
3559 """
3560 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iLine, sMessage,));
3561
3562 def raiseCommentError(self, iLineInComment, sMessage):
3563 """
3564 Similar to raiseError, but the line number is iLineInComment + self.iCommentLine.
3565 """
3566 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3567
3568 def error(self, sMessage):
3569 """
3570 Adds an error.
3571 returns False;
3572 """
3573 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iLine, sMessage,));
3574 return False;
3575
3576 def errorOnLine(self, iLine, sMessage):
3577 """
3578 Adds an error.
3579 returns False;
3580 """
3581 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, iLine, sMessage,));
3582 return False;
3583
3584 def errorComment(self, iLineInComment, sMessage):
3585 """
3586 Adds a comment error.
3587 returns False;
3588 """
3589 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
3590 return False;
3591
3592 def printErrors(self):
3593 """
3594 Print the errors to stderr.
3595 Returns number of errors.
3596 """
3597 if self.asErrors:
3598 sys.stderr.write(u''.join(self.asErrors));
3599 return len(self.asErrors);
3600
3601 def debug(self, sMessage):
3602 """
3603 For debugging.
3604 """
3605 if self.fDebug:
3606 print('debug: %s' % (sMessage,), file = sys.stderr);
3607
3608 def stripComments(self, sLine):
3609 """
3610 Returns sLine with comments stripped.
3611
3612 Complains if traces of incomplete multi-line comments are encountered.
3613 """
3614 sLine = self.oReComment.sub(" ", sLine);
3615 if sLine.find('/*') >= 0 or sLine.find('*/') >= 0:
3616 self.error('Unexpected multi-line comment will not be handled correctly. Please simplify.');
3617 return sLine;
3618
3619 def parseFunctionTable(self, sLine):
3620 """
3621 Parses a PFNIEMOP table, updating/checking the @oppfx value.
3622
3623 Note! Updates iLine as it consumes the whole table.
3624 """
3625
3626 #
3627 # Extract the table name.
3628 #
3629 sName = re.search(r' *([a-zA-Z_0-9]+) *\[', sLine).group(1);
3630 oMap = g_dInstructionMapsByIemName.get(sName);
3631 if not oMap:
3632 self.debug('No map for PFNIEMOP table: %s' % (sName,));
3633 oMap = self.oDefaultMap; # This is wrong wrong wrong.
3634
3635 #
3636 # All but the g_apfnOneByteMap & g_apfnEscF1_E0toFF tables uses four
3637 # entries per byte:
3638 # no prefix, 066h prefix, f3h prefix, f2h prefix
3639 # Those tables has 256 & 32 entries respectively.
3640 #
3641 cEntriesPerByte = 4;
3642 cValidTableLength = 1024;
3643 asPrefixes = ('none', '0x66', '0xf3', '0xf2');
3644
3645 oEntriesMatch = re.search(r'\[ *(256|32) *\]', sLine);
3646 if oEntriesMatch:
3647 cEntriesPerByte = 1;
3648 cValidTableLength = int(oEntriesMatch.group(1));
3649 asPrefixes = (None,);
3650
3651 #
3652 # The next line should be '{' and nothing else.
3653 #
3654 if self.iLine >= len(self.asLines) or not re.match('^ *{ *$', self.asLines[self.iLine]):
3655 return self.errorOnLine(self.iLine + 1, 'Expected lone "{" on line following PFNIEMOP table %s start' % (sName, ));
3656 self.iLine += 1;
3657
3658 #
3659 # Parse till we find the end of the table.
3660 #
3661 iEntry = 0;
3662 while self.iLine < len(self.asLines):
3663 # Get the next line and strip comments and spaces (assumes no
3664 # multi-line comments).
3665 sLine = self.asLines[self.iLine];
3666 self.iLine += 1;
3667 sLine = self.stripComments(sLine).strip();
3668
3669 # Split the line up into entries, expanding IEMOP_X4 usage.
3670 asEntries = sLine.split(',');
3671 for i in range(len(asEntries) - 1, -1, -1):
3672 sEntry = asEntries[i].strip();
3673 if sEntry.startswith('IEMOP_X4(') and sEntry[-1] == ')':
3674 sEntry = (sEntry[len('IEMOP_X4('):-1]).strip();
3675 asEntries.insert(i + 1, sEntry);
3676 asEntries.insert(i + 1, sEntry);
3677 asEntries.insert(i + 1, sEntry);
3678 if sEntry:
3679 asEntries[i] = sEntry;
3680 else:
3681 del asEntries[i];
3682
3683 # Process the entries.
3684 for sEntry in asEntries:
3685 if sEntry in ('};', '}'):
3686 if iEntry != cValidTableLength:
3687 return self.error('Wrong table length for %s: %#x, expected %#x' % (sName, iEntry, cValidTableLength, ));
3688 return True;
3689 if sEntry.startswith('iemOp_Invalid'):
3690 pass; # skip
3691 else:
3692 # Look up matching instruction by function.
3693 sPrefix = asPrefixes[iEntry % cEntriesPerByte];
3694 sOpcode = '%#04x' % (iEntry // cEntriesPerByte);
3695 aoInstr = g_dAllInstructionsByFunction.get(sEntry);
3696 if aoInstr:
3697 if not isinstance(aoInstr, list):
3698 aoInstr = [aoInstr,];
3699 oInstr = None;
3700 for oCurInstr in aoInstr:
3701 if oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix == sPrefix:
3702 pass;
3703 elif oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix is None:
3704 oCurInstr.sPrefix = sPrefix;
3705 elif oCurInstr.sOpcode is None and oCurInstr.sPrefix is None:
3706 oCurInstr.sOpcode = sOpcode;
3707 oCurInstr.sPrefix = sPrefix;
3708 else:
3709 continue;
3710 oInstr = oCurInstr;
3711 break;
3712 if not oInstr:
3713 oInstr = aoInstr[0].copy(oMap = oMap, sOpcode = sOpcode, sPrefix = sPrefix);
3714 aoInstr.append(oInstr);
3715 g_dAllInstructionsByFunction[sEntry] = aoInstr;
3716 g_aoAllInstructions.append(oInstr);
3717 oMap.aoInstructions.append(oInstr);
3718 else:
3719 self.debug('Function "%s", entry %#04x / byte %#04x in %s, is not associated with an instruction.'
3720 % (sEntry, iEntry, iEntry // cEntriesPerByte, sName,));
3721 iEntry += 1;
3722
3723 return self.error('Unexpected end of file in PFNIEMOP table');
3724
3725 def addInstruction(self, iLine = None):
3726 """
3727 Adds an instruction.
3728 """
3729 oInstr = Instruction(self.sSrcFile, self.iLine if iLine is None else iLine);
3730 g_aoAllInstructions.append(oInstr);
3731 self.aoCurInstrs.append(oInstr);
3732 return oInstr;
3733
3734 def deriveMnemonicAndOperandsFromStats(self, oInstr, sStats):
3735 """
3736 Derives the mnemonic and operands from a IEM stats base name like string.
3737 """
3738 if oInstr.sMnemonic is None:
3739 asWords = sStats.split('_');
3740 oInstr.sMnemonic = asWords[0].lower();
3741 if len(asWords) > 1 and not oInstr.aoOperands:
3742 for sType in asWords[1:]:
3743 if sType in g_kdOpTypes:
3744 oInstr.aoOperands.append(Operand(g_kdOpTypes[sType][1], sType));
3745 else:
3746 #return self.error('unknown operand type: %s (instruction: %s)' % (sType, oInstr))
3747 return False;
3748 return True;
3749
3750 def doneInstructionOne(self, oInstr, iLine):
3751 """
3752 Complete the parsing by processing, validating and expanding raw inputs.
3753 """
3754 assert oInstr.iLineCompleted is None;
3755 oInstr.iLineCompleted = iLine;
3756
3757 #
3758 # Specified instructions.
3759 #
3760 if oInstr.cOpTags > 0:
3761 if oInstr.sStats is None:
3762 pass;
3763
3764 #
3765 # Unspecified legacy stuff. We generally only got a few things to go on here.
3766 # /** Opcode 0x0f 0x00 /0. */
3767 # FNIEMOPRM_DEF(iemOp_Grp6_sldt)
3768 #
3769 else:
3770 #if oInstr.sRawOldOpcodes:
3771 #
3772 #if oInstr.sMnemonic:
3773 pass;
3774
3775 #
3776 # Common defaults.
3777 #
3778
3779 # Guess mnemonic and operands from stats if the former is missing.
3780 if oInstr.sMnemonic is None:
3781 if oInstr.sStats is not None:
3782 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sStats);
3783 elif oInstr.sFunction is not None:
3784 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sFunction.replace('iemOp_', ''));
3785
3786 # Derive the disassembler op enum constant from the mnemonic.
3787 if oInstr.sDisEnum is None and oInstr.sMnemonic is not None:
3788 oInstr.sDisEnum = 'OP_' + oInstr.sMnemonic.upper();
3789
3790 # Derive the IEM statistics base name from mnemonic and operand types.
3791 if oInstr.sStats is None:
3792 if oInstr.sFunction is not None:
3793 oInstr.sStats = oInstr.sFunction.replace('iemOp_', '');
3794 elif oInstr.sMnemonic is not None:
3795 oInstr.sStats = oInstr.sMnemonic;
3796 for oOperand in oInstr.aoOperands:
3797 if oOperand.sType:
3798 oInstr.sStats += '_' + oOperand.sType;
3799
3800 # Derive the IEM function name from mnemonic and operand types.
3801 if oInstr.sFunction is None:
3802 if oInstr.sMnemonic is not None:
3803 oInstr.sFunction = 'iemOp_' + oInstr.sMnemonic;
3804 for oOperand in oInstr.aoOperands:
3805 if oOperand.sType:
3806 oInstr.sFunction += '_' + oOperand.sType;
3807 elif oInstr.sStats:
3808 oInstr.sFunction = 'iemOp_' + oInstr.sStats;
3809
3810 #
3811 # Apply default map and then add the instruction to all it's groups.
3812 #
3813 if not oInstr.aoMaps:
3814 oInstr.aoMaps = [ self.oDefaultMap, ];
3815 for oMap in oInstr.aoMaps:
3816 oMap.aoInstructions.append(oInstr);
3817
3818 #
3819 # Derive encoding from operands and maps.
3820 #
3821 if oInstr.sEncoding is None:
3822 if not oInstr.aoOperands:
3823 if oInstr.fUnused and oInstr.sSubOpcode:
3824 oInstr.sEncoding = 'VEX.ModR/M' if oInstr.onlyInVexMaps() else 'ModR/M';
3825 else:
3826 oInstr.sEncoding = 'VEX.fixed' if oInstr.onlyInVexMaps() else 'fixed';
3827 elif oInstr.aoOperands[0].usesModRM():
3828 if (len(oInstr.aoOperands) >= 2 and oInstr.aoOperands[1].sWhere == 'vvvv') \
3829 or oInstr.onlyInVexMaps():
3830 oInstr.sEncoding = 'VEX.ModR/M';
3831 else:
3832 oInstr.sEncoding = 'ModR/M';
3833
3834 #
3835 # Check the opstat value and add it to the opstat indexed dictionary.
3836 #
3837 if oInstr.sStats:
3838 if oInstr.sStats not in g_dAllInstructionsByStat:
3839 g_dAllInstructionsByStat[oInstr.sStats] = oInstr;
3840 else:
3841 self.error('Duplicate opstat value "%s"\nnew: %s\nold: %s'
3842 % (oInstr.sStats, oInstr, g_dAllInstructionsByStat[oInstr.sStats],));
3843
3844 #
3845 # Add to function indexed dictionary. We allow multiple instructions per function.
3846 #
3847 if oInstr.sFunction:
3848 if oInstr.sFunction not in g_dAllInstructionsByFunction:
3849 g_dAllInstructionsByFunction[oInstr.sFunction] = [oInstr,];
3850 else:
3851 g_dAllInstructionsByFunction[oInstr.sFunction].append(oInstr);
3852
3853 #self.debug('%d..%d: %s; %d @op tags' % (oInstr.iLineCreated, oInstr.iLineCompleted, oInstr.sFunction, oInstr.cOpTags));
3854 return True;
3855
3856 def doneInstructions(self, iLineInComment = None, fEndOfFunction = False):
3857 """
3858 Done with current instruction.
3859 """
3860 for oInstr in self.aoCurInstrs:
3861 self.doneInstructionOne(oInstr, self.iLine if iLineInComment is None else self.iCommentLine + iLineInComment);
3862 if oInstr.fStub:
3863 self.cTotalStubs += 1;
3864
3865 self.cTotalInstr += len(self.aoCurInstrs);
3866
3867 self.sComment = '';
3868 self.aoCurInstrs = [];
3869 if fEndOfFunction:
3870 #self.debug('%s: oCurFunction=None' % (self.iLine, ));
3871 if self.oCurFunction:
3872 self.oCurFunction.complete(self.iLine, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine]);
3873 self.oCurFunction = None;
3874 self.iMcBlockInFunc = 0;
3875 return True;
3876
3877 def setInstrunctionAttrib(self, sAttrib, oValue, fOverwrite = False):
3878 """
3879 Sets the sAttrib of all current instruction to oValue. If fOverwrite
3880 is False, only None values and empty strings are replaced.
3881 """
3882 for oInstr in self.aoCurInstrs:
3883 if fOverwrite is not True:
3884 oOldValue = getattr(oInstr, sAttrib);
3885 if oOldValue is not None:
3886 continue;
3887 setattr(oInstr, sAttrib, oValue);
3888
3889 def setInstrunctionArrayAttrib(self, sAttrib, iEntry, oValue, fOverwrite = False):
3890 """
3891 Sets the iEntry of the array sAttrib of all current instruction to oValue.
3892 If fOverwrite is False, only None values and empty strings are replaced.
3893 """
3894 for oInstr in self.aoCurInstrs:
3895 aoArray = getattr(oInstr, sAttrib);
3896 while len(aoArray) <= iEntry:
3897 aoArray.append(None);
3898 if fOverwrite is True or aoArray[iEntry] is None:
3899 aoArray[iEntry] = oValue;
3900
3901 def parseCommentOldOpcode(self, asLines):
3902 """ Deals with 'Opcode 0xff /4' like comments """
3903 asWords = asLines[0].split();
3904 if len(asWords) >= 2 \
3905 and asWords[0] == 'Opcode' \
3906 and ( asWords[1].startswith('0x')
3907 or asWords[1].startswith('0X')):
3908 asWords = asWords[:1];
3909 for iWord, sWord in enumerate(asWords):
3910 if sWord.startswith('0X'):
3911 sWord = '0x' + sWord[:2];
3912 asWords[iWord] = asWords;
3913 self.setInstrunctionAttrib('sRawOldOpcodes', ' '.join(asWords));
3914
3915 return False;
3916
3917 def ensureInstructionForOpTag(self, iTagLine):
3918 """ Ensure there is an instruction for the op-tag being parsed. """
3919 if not self.aoCurInstrs:
3920 self.addInstruction(self.iCommentLine + iTagLine);
3921 for oInstr in self.aoCurInstrs:
3922 oInstr.cOpTags += 1;
3923 if oInstr.cOpTags == 1:
3924 self.cTotalTagged += 1;
3925 return self.aoCurInstrs[-1];
3926
3927 @staticmethod
3928 def flattenSections(aasSections):
3929 """
3930 Flattens multiline sections into stripped single strings.
3931 Returns list of strings, on section per string.
3932 """
3933 asRet = [];
3934 for asLines in aasSections:
3935 if asLines:
3936 asRet.append(' '.join([sLine.strip() for sLine in asLines]));
3937 return asRet;
3938
3939 @staticmethod
3940 def flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = '\n'):
3941 """
3942 Flattens sections into a simple stripped string with newlines as
3943 section breaks. The final section does not sport a trailing newline.
3944 """
3945 # Typical: One section with a single line.
3946 if len(aasSections) == 1 and len(aasSections[0]) == 1:
3947 return aasSections[0][0].strip();
3948
3949 sRet = '';
3950 for iSection, asLines in enumerate(aasSections):
3951 if asLines:
3952 if iSection > 0:
3953 sRet += sSectionSep;
3954 sRet += sLineSep.join([sLine.strip() for sLine in asLines]);
3955 return sRet;
3956
3957
3958
3959 ## @name Tag parsers
3960 ## @{
3961
3962 def parseTagOpBrief(self, sTag, aasSections, iTagLine, iEndLine):
3963 """
3964 Tag: @opbrief
3965 Value: Text description, multiple sections, appended.
3966
3967 Brief description. If not given, it's the first sentence from @opdesc.
3968 """
3969 oInstr = self.ensureInstructionForOpTag(iTagLine);
3970
3971 # Flatten and validate the value.
3972 sBrief = self.flattenAllSections(aasSections);
3973 if not sBrief:
3974 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
3975 if sBrief[-1] != '.':
3976 sBrief = sBrief + '.';
3977 if len(sBrief) > 180:
3978 return self.errorComment(iTagLine, '%s: value too long (max 180 chars): %s' % (sTag, sBrief));
3979 offDot = sBrief.find('.');
3980 while 0 <= offDot < len(sBrief) - 1 and sBrief[offDot + 1] != ' ':
3981 offDot = sBrief.find('.', offDot + 1);
3982 if offDot >= 0 and offDot != len(sBrief) - 1:
3983 return self.errorComment(iTagLine, '%s: only one sentence: %s' % (sTag, sBrief));
3984
3985 # Update the instruction.
3986 if oInstr.sBrief is not None:
3987 return self.errorComment(iTagLine, '%s: attempting to overwrite brief "%s" with "%s"'
3988 % (sTag, oInstr.sBrief, sBrief,));
3989 _ = iEndLine;
3990 return True;
3991
3992 def parseTagOpDesc(self, sTag, aasSections, iTagLine, iEndLine):
3993 """
3994 Tag: @opdesc
3995 Value: Text description, multiple sections, appended.
3996
3997 It is used to describe instructions.
3998 """
3999 oInstr = self.ensureInstructionForOpTag(iTagLine);
4000 if aasSections:
4001 oInstr.asDescSections.extend(self.flattenSections(aasSections));
4002 return True;
4003
4004 _ = sTag; _ = iEndLine;
4005 return True;
4006
4007 def parseTagOpMnemonic(self, sTag, aasSections, iTagLine, iEndLine):
4008 """
4009 Tag: @opmenmonic
4010 Value: mnemonic
4011
4012 The 'mnemonic' value must be a valid C identifier string. Because of
4013 prefixes, groups and whatnot, there times when the mnemonic isn't that
4014 of an actual assembler mnemonic.
4015 """
4016 oInstr = self.ensureInstructionForOpTag(iTagLine);
4017
4018 # Flatten and validate the value.
4019 sMnemonic = self.flattenAllSections(aasSections);
4020 if not self.oReMnemonic.match(sMnemonic):
4021 return self.errorComment(iTagLine, '%s: invalid menmonic name: "%s"' % (sTag, sMnemonic,));
4022 if oInstr.sMnemonic is not None:
4023 return self.errorComment(iTagLine, '%s: attempting to overwrite menmonic "%s" with "%s"'
4024 % (sTag, oInstr.sMnemonic, sMnemonic,));
4025 oInstr.sMnemonic = sMnemonic
4026
4027 _ = iEndLine;
4028 return True;
4029
4030 def parseTagOpOperandN(self, sTag, aasSections, iTagLine, iEndLine):
4031 """
4032 Tags: @op1, @op2, @op3, @op4
4033 Value: [where:]type
4034
4035 The 'where' value indicates where the operand is found, like the 'reg'
4036 part of the ModR/M encoding. See Instruction.kdOperandLocations for
4037 a list.
4038
4039 The 'type' value indicates the operand type. These follow the types
4040 given in the opcode tables in the CPU reference manuals.
4041 See Instruction.kdOperandTypes for a list.
4042
4043 """
4044 oInstr = self.ensureInstructionForOpTag(iTagLine);
4045 idxOp = int(sTag[-1]) - 1;
4046 assert 0 <= idxOp < 4;
4047
4048 # flatten, split up, and validate the "where:type" value.
4049 sFlattened = self.flattenAllSections(aasSections);
4050 asSplit = sFlattened.split(':');
4051 if len(asSplit) == 1:
4052 sType = asSplit[0];
4053 sWhere = None;
4054 elif len(asSplit) == 2:
4055 (sWhere, sType) = asSplit;
4056 else:
4057 return self.errorComment(iTagLine, 'expected %s value on format "[<where>:]<type>" not "%s"' % (sTag, sFlattened,));
4058
4059 if sType not in g_kdOpTypes:
4060 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
4061 % (sTag, sType, ', '.join(g_kdOpTypes.keys()),));
4062 if sWhere is None:
4063 sWhere = g_kdOpTypes[sType][1];
4064 elif sWhere not in g_kdOpLocations:
4065 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
4066 % (sTag, sWhere, ', '.join(g_kdOpLocations.keys()),));
4067
4068 # Insert the operand, refusing to overwrite an existing one.
4069 while idxOp >= len(oInstr.aoOperands):
4070 oInstr.aoOperands.append(None);
4071 if oInstr.aoOperands[idxOp] is not None:
4072 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s:%s" with "%s:%s"'
4073 % ( sTag, oInstr.aoOperands[idxOp].sWhere, oInstr.aoOperands[idxOp].sType,
4074 sWhere, sType,));
4075 oInstr.aoOperands[idxOp] = Operand(sWhere, sType);
4076
4077 _ = iEndLine;
4078 return True;
4079
4080 def parseTagOpMaps(self, sTag, aasSections, iTagLine, iEndLine):
4081 """
4082 Tag: @opmaps
4083 Value: map[,map2]
4084
4085 Indicates which maps the instruction is in. There is a default map
4086 associated with each input file.
4087 """
4088 oInstr = self.ensureInstructionForOpTag(iTagLine);
4089
4090 # Flatten, split up and validate the value.
4091 sFlattened = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',');
4092 asMaps = sFlattened.split(',');
4093 if not asMaps:
4094 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
4095 for sMap in asMaps:
4096 if sMap not in g_dInstructionMaps:
4097 return self.errorComment(iTagLine, '%s: invalid map value: %s (valid values: %s)'
4098 % (sTag, sMap, ', '.join(g_dInstructionMaps.keys()),));
4099
4100 # Add the maps to the current list. Throw errors on duplicates.
4101 for oMap in oInstr.aoMaps:
4102 if oMap.sName in asMaps:
4103 return self.errorComment(iTagLine, '%s: duplicate map assignment: %s' % (sTag, oMap.sName));
4104
4105 for sMap in asMaps:
4106 oMap = g_dInstructionMaps[sMap];
4107 if oMap not in oInstr.aoMaps:
4108 oInstr.aoMaps.append(oMap);
4109 else:
4110 self.errorComment(iTagLine, '%s: duplicate map assignment (input): %s' % (sTag, sMap));
4111
4112 _ = iEndLine;
4113 return True;
4114
4115 def parseTagOpPfx(self, sTag, aasSections, iTagLine, iEndLine):
4116 """
4117 Tag: @oppfx
4118 Value: n/a|none|0x66|0xf3|0xf2
4119
4120 Required prefix for the instruction. (In a (E)VEX context this is the
4121 value of the 'pp' field rather than an actual prefix.)
4122 """
4123 oInstr = self.ensureInstructionForOpTag(iTagLine);
4124
4125 # Flatten and validate the value.
4126 sFlattened = self.flattenAllSections(aasSections);
4127 asPrefixes = sFlattened.split();
4128 if len(asPrefixes) > 1:
4129 return self.errorComment(iTagLine, '%s: max one prefix: %s' % (sTag, asPrefixes,));
4130
4131 sPrefix = asPrefixes[0].lower();
4132 if sPrefix == 'none':
4133 sPrefix = 'none';
4134 elif sPrefix == 'n/a':
4135 sPrefix = None;
4136 else:
4137 if len(sPrefix) == 2:
4138 sPrefix = '0x' + sPrefix;
4139 if not _isValidOpcodeByte(sPrefix):
4140 return self.errorComment(iTagLine, '%s: invalid prefix: %s' % (sTag, sPrefix,));
4141
4142 if sPrefix is not None and sPrefix not in g_kdPrefixes:
4143 return self.errorComment(iTagLine, '%s: invalid prefix: %s (valid %s)' % (sTag, sPrefix, g_kdPrefixes,));
4144
4145 # Set it.
4146 if oInstr.sPrefix is not None:
4147 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sPrefix, sPrefix,));
4148 oInstr.sPrefix = sPrefix;
4149
4150 _ = iEndLine;
4151 return True;
4152
4153 def parseTagOpcode(self, sTag, aasSections, iTagLine, iEndLine):
4154 """
4155 Tag: @opcode
4156 Value: 0x?? | /reg (TODO: | mr/reg | 11 /reg | !11 /reg | 11 mr/reg | !11 mr/reg)
4157
4158 The opcode byte or sub-byte for the instruction in the context of a map.
4159 """
4160 oInstr = self.ensureInstructionForOpTag(iTagLine);
4161
4162 # Flatten and validate the value.
4163 sOpcode = self.flattenAllSections(aasSections);
4164 if _isValidOpcodeByte(sOpcode):
4165 pass;
4166 elif len(sOpcode) == 2 and sOpcode.startswith('/') and sOpcode[-1] in '012345678':
4167 pass;
4168 elif len(sOpcode) == 4 and sOpcode.startswith('11/') and sOpcode[-1] in '012345678':
4169 pass;
4170 elif len(sOpcode) == 5 and sOpcode.startswith('!11/') and sOpcode[-1] in '012345678':
4171 pass;
4172 else:
4173 return self.errorComment(iTagLine, '%s: invalid opcode: %s' % (sTag, sOpcode,));
4174
4175 # Set it.
4176 if oInstr.sOpcode is not None:
4177 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sOpcode, sOpcode,));
4178 oInstr.sOpcode = sOpcode;
4179
4180 _ = iEndLine;
4181 return True;
4182
4183 def parseTagOpcodeSub(self, sTag, aasSections, iTagLine, iEndLine):
4184 """
4185 Tag: @opcodesub
4186 Value: none | 11 mr/reg | !11 mr/reg | rex.w=0 | rex.w=1 | vex.l=0 | vex.l=1
4187 | 11 mr/reg vex.l=0 | 11 mr/reg vex.l=1 | !11 mr/reg vex.l=0 | !11 mr/reg vex.l=1
4188
4189 This is a simple way of dealing with encodings where the mod=3 and mod!=3
4190 represents exactly two different instructions. The more proper way would
4191 be to go via maps with two members, but this is faster.
4192 """
4193 oInstr = self.ensureInstructionForOpTag(iTagLine);
4194
4195 # Flatten and validate the value.
4196 sSubOpcode = self.flattenAllSections(aasSections);
4197 if sSubOpcode not in g_kdSubOpcodes:
4198 return self.errorComment(iTagLine, '%s: invalid sub opcode: %s (valid: 11, !11, none)' % (sTag, sSubOpcode,));
4199 sSubOpcode = g_kdSubOpcodes[sSubOpcode][0];
4200
4201 # Set it.
4202 if oInstr.sSubOpcode is not None:
4203 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4204 % ( sTag, oInstr.sSubOpcode, sSubOpcode,));
4205 oInstr.sSubOpcode = sSubOpcode;
4206
4207 _ = iEndLine;
4208 return True;
4209
4210 def parseTagOpEnc(self, sTag, aasSections, iTagLine, iEndLine):
4211 """
4212 Tag: @openc
4213 Value: ModR/M|fixed|prefix|<map name>
4214
4215 The instruction operand encoding style.
4216 """
4217 oInstr = self.ensureInstructionForOpTag(iTagLine);
4218
4219 # Flatten and validate the value.
4220 sEncoding = self.flattenAllSections(aasSections);
4221 if sEncoding in g_kdEncodings:
4222 pass;
4223 elif sEncoding in g_dInstructionMaps:
4224 pass;
4225 elif not _isValidOpcodeByte(sEncoding):
4226 return self.errorComment(iTagLine, '%s: invalid encoding: %s' % (sTag, sEncoding,));
4227
4228 # Set it.
4229 if oInstr.sEncoding is not None:
4230 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
4231 % ( sTag, oInstr.sEncoding, sEncoding,));
4232 oInstr.sEncoding = sEncoding;
4233
4234 _ = iEndLine;
4235 return True;
4236
4237 ## EFlags tag to Instruction attribute name.
4238 kdOpFlagToAttr = {
4239 '@opfltest': 'asFlTest',
4240 '@opflmodify': 'asFlModify',
4241 '@opflundef': 'asFlUndefined',
4242 '@opflset': 'asFlSet',
4243 '@opflclear': 'asFlClear',
4244 };
4245
4246 def parseTagOpEFlags(self, sTag, aasSections, iTagLine, iEndLine):
4247 """
4248 Tags: @opfltest, @opflmodify, @opflundef, @opflset, @opflclear
4249 Value: <eflags specifier>
4250
4251 """
4252 oInstr = self.ensureInstructionForOpTag(iTagLine);
4253
4254 # Flatten, split up and validate the values.
4255 asFlags = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',').split(',');
4256 if len(asFlags) == 1 and asFlags[0].lower() == 'none':
4257 asFlags = [];
4258 else:
4259 fRc = True;
4260 for iFlag, sFlag in enumerate(asFlags):
4261 if sFlag not in g_kdEFlagsMnemonics:
4262 if sFlag.strip() in g_kdEFlagsMnemonics:
4263 asFlags[iFlag] = sFlag.strip();
4264 else:
4265 fRc = self.errorComment(iTagLine, '%s: invalid EFLAGS value: %s' % (sTag, sFlag,));
4266 if not fRc:
4267 return False;
4268
4269 # Set them.
4270 asOld = getattr(oInstr, self.kdOpFlagToAttr[sTag]);
4271 if asOld is not None:
4272 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, asOld, asFlags,));
4273 setattr(oInstr, self.kdOpFlagToAttr[sTag], asFlags);
4274
4275 _ = iEndLine;
4276 return True;
4277
4278 def parseTagOpHints(self, sTag, aasSections, iTagLine, iEndLine):
4279 """
4280 Tag: @ophints
4281 Value: Comma or space separated list of flags and hints.
4282
4283 This covers the disassembler flags table and more.
4284 """
4285 oInstr = self.ensureInstructionForOpTag(iTagLine);
4286
4287 # Flatten as a space separated list, split it up and validate the values.
4288 asHints = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4289 if len(asHints) == 1 and asHints[0].lower() == 'none':
4290 asHints = [];
4291 else:
4292 fRc = True;
4293 for iHint, sHint in enumerate(asHints):
4294 if sHint not in g_kdHints:
4295 if sHint.strip() in g_kdHints:
4296 sHint[iHint] = sHint.strip();
4297 else:
4298 fRc = self.errorComment(iTagLine, '%s: invalid hint value: %s' % (sTag, sHint,));
4299 if not fRc:
4300 return False;
4301
4302 # Append them.
4303 for sHint in asHints:
4304 if sHint not in oInstr.dHints:
4305 oInstr.dHints[sHint] = True; # (dummy value, using dictionary for speed)
4306 else:
4307 self.errorComment(iTagLine, '%s: duplicate hint: %s' % ( sTag, sHint,));
4308
4309 _ = iEndLine;
4310 return True;
4311
4312 def parseTagOpDisEnum(self, sTag, aasSections, iTagLine, iEndLine):
4313 """
4314 Tag: @opdisenum
4315 Value: OP_XXXX
4316
4317 This is for select a specific (legacy) disassembler enum value for the
4318 instruction.
4319 """
4320 oInstr = self.ensureInstructionForOpTag(iTagLine);
4321
4322 # Flatten and split.
4323 asWords = self.flattenAllSections(aasSections).split();
4324 if len(asWords) != 1:
4325 self.errorComment(iTagLine, '%s: expected exactly one value: %s' % (sTag, asWords,));
4326 if not asWords:
4327 return False;
4328 sDisEnum = asWords[0];
4329 if not self.oReDisEnum.match(sDisEnum):
4330 return self.errorComment(iTagLine, '%s: invalid disassembler OP_XXXX enum: %s (pattern: %s)'
4331 % (sTag, sDisEnum, self.oReDisEnum.pattern));
4332
4333 # Set it.
4334 if oInstr.sDisEnum is not None:
4335 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % (sTag, oInstr.sDisEnum, sDisEnum,));
4336 oInstr.sDisEnum = sDisEnum;
4337
4338 _ = iEndLine;
4339 return True;
4340
4341 def parseTagOpMinCpu(self, sTag, aasSections, iTagLine, iEndLine):
4342 """
4343 Tag: @opmincpu
4344 Value: <simple CPU name>
4345
4346 Indicates when this instruction was introduced.
4347 """
4348 oInstr = self.ensureInstructionForOpTag(iTagLine);
4349
4350 # Flatten the value, split into words, make sure there's just one, valid it.
4351 asCpus = self.flattenAllSections(aasSections).split();
4352 if len(asCpus) > 1:
4353 self.errorComment(iTagLine, '%s: exactly one CPU name, please: %s' % (sTag, ' '.join(asCpus),));
4354
4355 sMinCpu = asCpus[0];
4356 if sMinCpu in g_kdCpuNames:
4357 oInstr.sMinCpu = sMinCpu;
4358 else:
4359 return self.errorComment(iTagLine, '%s: invalid CPU name: %s (names: %s)'
4360 % (sTag, sMinCpu, ','.join(sorted(g_kdCpuNames)),));
4361
4362 # Set it.
4363 if oInstr.sMinCpu is None:
4364 oInstr.sMinCpu = sMinCpu;
4365 elif oInstr.sMinCpu != sMinCpu:
4366 self.errorComment(iTagLine, '%s: attemting to overwrite "%s" with "%s"' % (sTag, oInstr.sMinCpu, sMinCpu,));
4367
4368 _ = iEndLine;
4369 return True;
4370
4371 def parseTagOpCpuId(self, sTag, aasSections, iTagLine, iEndLine):
4372 """
4373 Tag: @opcpuid
4374 Value: none | <CPUID flag specifier>
4375
4376 CPUID feature bit which is required for the instruction to be present.
4377 """
4378 oInstr = self.ensureInstructionForOpTag(iTagLine);
4379
4380 # Flatten as a space separated list, split it up and validate the values.
4381 asCpuIds = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
4382 if len(asCpuIds) == 1 and asCpuIds[0].lower() == 'none':
4383 asCpuIds = [];
4384 else:
4385 fRc = True;
4386 for iCpuId, sCpuId in enumerate(asCpuIds):
4387 if sCpuId not in g_kdCpuIdFlags:
4388 if sCpuId.strip() in g_kdCpuIdFlags:
4389 sCpuId[iCpuId] = sCpuId.strip();
4390 else:
4391 fRc = self.errorComment(iTagLine, '%s: invalid CPUID value: %s' % (sTag, sCpuId,));
4392 if not fRc:
4393 return False;
4394
4395 # Append them.
4396 for sCpuId in asCpuIds:
4397 if sCpuId not in oInstr.asCpuIds:
4398 oInstr.asCpuIds.append(sCpuId);
4399 else:
4400 self.errorComment(iTagLine, '%s: duplicate CPUID: %s' % ( sTag, sCpuId,));
4401
4402 _ = iEndLine;
4403 return True;
4404
4405 def parseTagOpGroup(self, sTag, aasSections, iTagLine, iEndLine):
4406 """
4407 Tag: @opgroup
4408 Value: op_grp1[_subgrp2[_subsubgrp3]]
4409
4410 Instruction grouping.
4411 """
4412 oInstr = self.ensureInstructionForOpTag(iTagLine);
4413
4414 # Flatten as a space separated list, split it up and validate the values.
4415 asGroups = self.flattenAllSections(aasSections).split();
4416 if len(asGroups) != 1:
4417 return self.errorComment(iTagLine, '%s: exactly one group, please: %s' % (sTag, asGroups,));
4418 sGroup = asGroups[0];
4419 if not self.oReGroupName.match(sGroup):
4420 return self.errorComment(iTagLine, '%s: invalid group name: %s (valid: %s)'
4421 % (sTag, sGroup, self.oReGroupName.pattern));
4422
4423 # Set it.
4424 if oInstr.sGroup is not None:
4425 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sGroup, sGroup,));
4426 oInstr.sGroup = sGroup;
4427
4428 _ = iEndLine;
4429 return True;
4430
4431 def parseTagOpUnusedInvalid(self, sTag, aasSections, iTagLine, iEndLine):
4432 """
4433 Tag: @opunused, @opinvalid, @opinvlstyle
4434 Value: <invalid opcode behaviour style>
4435
4436 The @opunused indicates the specification is for a currently unused
4437 instruction encoding.
4438
4439 The @opinvalid indicates the specification is for an invalid currently
4440 instruction encoding (like UD2).
4441
4442 The @opinvlstyle just indicates how CPUs decode the instruction when
4443 not supported (@opcpuid, @opmincpu) or disabled.
4444 """
4445 oInstr = self.ensureInstructionForOpTag(iTagLine);
4446
4447 # Flatten as a space separated list, split it up and validate the values.
4448 asStyles = self.flattenAllSections(aasSections).split();
4449 if len(asStyles) != 1:
4450 return self.errorComment(iTagLine, '%s: exactly one invalid behviour style, please: %s' % (sTag, asStyles,));
4451 sStyle = asStyles[0];
4452 if sStyle not in g_kdInvalidStyles:
4453 return self.errorComment(iTagLine, '%s: invalid invalid behaviour style: %s (valid: %s)'
4454 % (sTag, sStyle, g_kdInvalidStyles.keys(),));
4455 # Set it.
4456 if oInstr.sInvalidStyle is not None:
4457 return self.errorComment(iTagLine,
4458 '%s: attempting to overwrite "%s" with "%s" (only one @opunused, @opinvalid, @opinvlstyle)'
4459 % ( sTag, oInstr.sInvalidStyle, sStyle,));
4460 oInstr.sInvalidStyle = sStyle;
4461 if sTag == '@opunused':
4462 oInstr.fUnused = True;
4463 elif sTag == '@opinvalid':
4464 oInstr.fInvalid = True;
4465
4466 _ = iEndLine;
4467 return True;
4468
4469 def parseTagOpTest(self, sTag, aasSections, iTagLine, iEndLine): # pylint: disable=too-many-locals
4470 """
4471 Tag: @optest
4472 Value: [<selectors>[ ]?] <inputs> -> <outputs>
4473 Example: mode==64bit / in1=0xfffffffe:dw in2=1:dw -> out1=0xffffffff:dw outfl=a?,p?
4474
4475 The main idea here is to generate basic instruction tests.
4476
4477 The probably simplest way of handling the diverse input, would be to use
4478 it to produce size optimized byte code for a simple interpreter that
4479 modifies the register input and output states.
4480
4481 An alternative to the interpreter would be creating multiple tables,
4482 but that becomes rather complicated wrt what goes where and then to use
4483 them in an efficient manner.
4484 """
4485 oInstr = self.ensureInstructionForOpTag(iTagLine);
4486
4487 #
4488 # Do it section by section.
4489 #
4490 for asSectionLines in aasSections:
4491 #
4492 # Sort the input into outputs, inputs and selector conditions.
4493 #
4494 sFlatSection = self.flattenAllSections([asSectionLines,]);
4495 if not sFlatSection:
4496 self.errorComment(iTagLine, '%s: missing value (dbg: aasSections=%s)' % ( sTag, aasSections));
4497 continue;
4498 oTest = InstructionTest(oInstr);
4499
4500 asSelectors = [];
4501 asInputs = [];
4502 asOutputs = [];
4503 asCur = asOutputs;
4504 fRc = True;
4505 asWords = sFlatSection.split();
4506 for iWord in range(len(asWords) - 1, -1, -1):
4507 sWord = asWords[iWord];
4508 # Check for array switchers.
4509 if sWord == '->':
4510 if asCur != asOutputs:
4511 fRc = self.errorComment(iTagLine, '%s: "->" shall only occure once: %s' % (sTag, sFlatSection,));
4512 break;
4513 asCur = asInputs;
4514 elif sWord == '/':
4515 if asCur != asInputs:
4516 fRc = self.errorComment(iTagLine, '%s: "/" shall only occure once: %s' % (sTag, sFlatSection,));
4517 break;
4518 asCur = asSelectors;
4519 else:
4520 asCur.insert(0, sWord);
4521
4522 #
4523 # Validate and add selectors.
4524 #
4525 for sCond in asSelectors:
4526 sCondExp = TestSelector.kdPredicates.get(sCond, sCond);
4527 oSelector = None;
4528 for sOp in TestSelector.kasCompareOps:
4529 off = sCondExp.find(sOp);
4530 if off >= 0:
4531 sVariable = sCondExp[:off];
4532 sValue = sCondExp[off + len(sOp):];
4533 if sVariable in TestSelector.kdVariables:
4534 if sValue in TestSelector.kdVariables[sVariable]:
4535 oSelector = TestSelector(sVariable, sOp, sValue);
4536 else:
4537 self.errorComment(iTagLine, '%s: invalid condition value "%s" in "%s" (valid: %s)'
4538 % ( sTag, sValue, sCond,
4539 TestSelector.kdVariables[sVariable].keys(),));
4540 else:
4541 self.errorComment(iTagLine, '%s: invalid condition variable "%s" in "%s" (valid: %s)'
4542 % ( sTag, sVariable, sCond, TestSelector.kdVariables.keys(),));
4543 break;
4544 if oSelector is not None:
4545 for oExisting in oTest.aoSelectors:
4546 if oExisting.sVariable == oSelector.sVariable:
4547 self.errorComment(iTagLine, '%s: already have a selector for variable "%s" (existing: %s, new: %s)'
4548 % ( sTag, oSelector.sVariable, oExisting, oSelector,));
4549 oTest.aoSelectors.append(oSelector);
4550 else:
4551 fRc = self.errorComment(iTagLine, '%s: failed to parse selector: %s' % ( sTag, sCond,));
4552
4553 #
4554 # Validate outputs and inputs, adding them to the test as we go along.
4555 #
4556 for asItems, sDesc, aoDst in [ (asInputs, 'input', oTest.aoInputs), (asOutputs, 'output', oTest.aoOutputs)]:
4557 asValidFieldKinds = [ 'both', sDesc, ];
4558 for sItem in asItems:
4559 oItem = None;
4560 for sOp in TestInOut.kasOperators:
4561 off = sItem.find(sOp);
4562 if off < 0:
4563 continue;
4564 sField = sItem[:off];
4565 sValueType = sItem[off + len(sOp):];
4566 if sField in TestInOut.kdFields \
4567 and TestInOut.kdFields[sField][1] in asValidFieldKinds:
4568 asSplit = sValueType.split(':', 1);
4569 sValue = asSplit[0];
4570 sType = asSplit[1] if len(asSplit) > 1 else TestInOut.kdFields[sField][0];
4571 if sType in TestInOut.kdTypes:
4572 oValid = TestInOut.kdTypes[sType].validate(sValue);
4573 if oValid is True:
4574 if not TestInOut.kdTypes[sType].isAndOrPair(sValue) or sOp == '&|=':
4575 oItem = TestInOut(sField, sOp, sValue, sType);
4576 else:
4577 self.errorComment(iTagLine, '%s: and-or %s value "%s" can only be used with "&|="'
4578 % ( sTag, sDesc, sItem, ));
4579 else:
4580 self.errorComment(iTagLine, '%s: invalid %s value "%s" in "%s" (type: %s): %s'
4581 % ( sTag, sDesc, sValue, sItem, sType, oValid, ));
4582 else:
4583 self.errorComment(iTagLine, '%s: invalid %s type "%s" in "%s" (valid types: %s)'
4584 % ( sTag, sDesc, sType, sItem, TestInOut.kdTypes.keys(),));
4585 else:
4586 self.errorComment(iTagLine, '%s: invalid %s field "%s" in "%s"\nvalid fields: %s'
4587 % ( sTag, sDesc, sField, sItem,
4588 ', '.join([sKey for sKey, asVal in TestInOut.kdFields.items()
4589 if asVal[1] in asValidFieldKinds]),));
4590 break;
4591 if oItem is not None:
4592 for oExisting in aoDst:
4593 if oExisting.sField == oItem.sField and oExisting.sOp == oItem.sOp:
4594 self.errorComment(iTagLine,
4595 '%s: already have a "%s" assignment for field "%s" (existing: %s, new: %s)'
4596 % ( sTag, oItem.sOp, oItem.sField, oExisting, oItem,));
4597 aoDst.append(oItem);
4598 else:
4599 fRc = self.errorComment(iTagLine, '%s: failed to parse assignment: %s' % ( sTag, sItem,));
4600
4601 #
4602 # .
4603 #
4604 if fRc:
4605 oInstr.aoTests.append(oTest);
4606 else:
4607 self.errorComment(iTagLine, '%s: failed to parse test: %s' % (sTag, ' '.join(asWords),));
4608 self.errorComment(iTagLine, '%s: asSelectors=%s / asInputs=%s -> asOutputs=%s'
4609 % (sTag, asSelectors, asInputs, asOutputs,));
4610
4611 _ = iEndLine;
4612 return True;
4613
4614 def parseTagOpTestNum(self, sTag, aasSections, iTagLine, iEndLine):
4615 """
4616 Numbered @optest tag. Either @optest42 or @optest[42].
4617 """
4618 oInstr = self.ensureInstructionForOpTag(iTagLine);
4619
4620 iTest = 0;
4621 if sTag[-1] == ']':
4622 iTest = int(sTag[8:-1]);
4623 else:
4624 iTest = int(sTag[7:]);
4625
4626 if iTest != len(oInstr.aoTests):
4627 self.errorComment(iTagLine, '%s: incorrect test number: %u, actual %u' % (sTag, iTest, len(oInstr.aoTests),));
4628 return self.parseTagOpTest(sTag, aasSections, iTagLine, iEndLine);
4629
4630 def parseTagOpTestIgnore(self, sTag, aasSections, iTagLine, iEndLine):
4631 """
4632 Tag: @optestign | @optestignore
4633 Value: <value is ignored>
4634
4635 This is a simple trick to ignore a test while debugging another.
4636
4637 See also @oponlytest.
4638 """
4639 _ = sTag; _ = aasSections; _ = iTagLine; _ = iEndLine;
4640 return True;
4641
4642 def parseTagOpCopyTests(self, sTag, aasSections, iTagLine, iEndLine):
4643 """
4644 Tag: @opcopytests
4645 Value: <opstat | function> [..]
4646 Example: @opcopytests add_Eb_Gb
4647
4648 Trick to avoid duplicating tests for different encodings of the same
4649 operation.
4650 """
4651 oInstr = self.ensureInstructionForOpTag(iTagLine);
4652
4653 # Flatten, validate and append the copy job to the instruction. We execute
4654 # them after parsing all the input so we can handle forward references.
4655 asToCopy = self.flattenAllSections(aasSections).split();
4656 if not asToCopy:
4657 return self.errorComment(iTagLine, '%s: requires at least on reference value' % (sTag,));
4658 for sToCopy in asToCopy:
4659 if sToCopy not in oInstr.asCopyTests:
4660 if self.oReStatsName.match(sToCopy) or self.oReFunctionName.match(sToCopy):
4661 oInstr.asCopyTests.append(sToCopy);
4662 else:
4663 self.errorComment(iTagLine, '%s: invalid instruction reference (opstat or function) "%s" (valid: %s or %s)'
4664 % (sTag, sToCopy, self.oReStatsName.pattern, self.oReFunctionName.pattern));
4665 else:
4666 self.errorComment(iTagLine, '%s: ignoring duplicate "%s"' % (sTag, sToCopy,));
4667
4668 _ = iEndLine;
4669 return True;
4670
4671 def parseTagOpOnlyTest(self, sTag, aasSections, iTagLine, iEndLine):
4672 """
4673 Tag: @oponlytest | @oponly
4674 Value: none
4675
4676 Only test instructions with this tag. This is a trick that is handy
4677 for singling out one or two new instructions or tests.
4678
4679 See also @optestignore.
4680 """
4681 oInstr = self.ensureInstructionForOpTag(iTagLine);
4682
4683 # Validate and add instruction to only test dictionary.
4684 sValue = self.flattenAllSections(aasSections).strip();
4685 if sValue:
4686 return self.errorComment(iTagLine, '%s: does not take any value: %s' % (sTag, sValue));
4687
4688 if oInstr not in g_aoOnlyTestInstructions:
4689 g_aoOnlyTestInstructions.append(oInstr);
4690
4691 _ = iEndLine;
4692 return True;
4693
4694 def parseTagOpXcptType(self, sTag, aasSections, iTagLine, iEndLine):
4695 """
4696 Tag: @opxcpttype
4697 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]
4698
4699 Sets the SSE or AVX exception type (see SDMv2 2.4, 2.7).
4700 """
4701 oInstr = self.ensureInstructionForOpTag(iTagLine);
4702
4703 # Flatten as a space separated list, split it up and validate the values.
4704 asTypes = self.flattenAllSections(aasSections).split();
4705 if len(asTypes) != 1:
4706 return self.errorComment(iTagLine, '%s: exactly one invalid exception type, please: %s' % (sTag, asTypes,));
4707 sType = asTypes[0];
4708 if sType not in g_kdXcptTypes:
4709 return self.errorComment(iTagLine, '%s: invalid invalid exception type: %s (valid: %s)'
4710 % (sTag, sType, sorted(g_kdXcptTypes.keys()),));
4711 # Set it.
4712 if oInstr.sXcptType is not None:
4713 return self.errorComment(iTagLine,
4714 '%s: attempting to overwrite "%s" with "%s" (only one @opxcpttype)'
4715 % ( sTag, oInstr.sXcptType, sType,));
4716 oInstr.sXcptType = sType;
4717
4718 _ = iEndLine;
4719 return True;
4720
4721 def parseTagOpFunction(self, sTag, aasSections, iTagLine, iEndLine):
4722 """
4723 Tag: @opfunction
4724 Value: <VMM function name>
4725
4726 This is for explicitly setting the IEM function name. Normally we pick
4727 this up from the FNIEMOP_XXX macro invocation after the description, or
4728 generate it from the mnemonic and operands.
4729
4730 It it thought it maybe necessary to set it when specifying instructions
4731 which implementation isn't following immediately or aren't implemented yet.
4732 """
4733 oInstr = self.ensureInstructionForOpTag(iTagLine);
4734
4735 # Flatten and validate the value.
4736 sFunction = self.flattenAllSections(aasSections);
4737 if not self.oReFunctionName.match(sFunction):
4738 return self.errorComment(iTagLine, '%s: invalid VMM function name: "%s" (valid: %s)'
4739 % (sTag, sFunction, self.oReFunctionName.pattern));
4740
4741 if oInstr.sFunction is not None:
4742 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM function name "%s" with "%s"'
4743 % (sTag, oInstr.sFunction, sFunction,));
4744 oInstr.sFunction = sFunction;
4745
4746 _ = iEndLine;
4747 return True;
4748
4749 def parseTagOpStats(self, sTag, aasSections, iTagLine, iEndLine):
4750 """
4751 Tag: @opstats
4752 Value: <VMM statistics base name>
4753
4754 This is for explicitly setting the statistics name. Normally we pick
4755 this up from the IEMOP_MNEMONIC macro invocation, or generate it from
4756 the mnemonic and operands.
4757
4758 It it thought it maybe necessary to set it when specifying instructions
4759 which implementation isn't following immediately or aren't implemented yet.
4760 """
4761 oInstr = self.ensureInstructionForOpTag(iTagLine);
4762
4763 # Flatten and validate the value.
4764 sStats = self.flattenAllSections(aasSections);
4765 if not self.oReStatsName.match(sStats):
4766 return self.errorComment(iTagLine, '%s: invalid VMM statistics name: "%s" (valid: %s)'
4767 % (sTag, sStats, self.oReStatsName.pattern));
4768
4769 if oInstr.sStats is not None:
4770 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM statistics base name "%s" with "%s"'
4771 % (sTag, oInstr.sStats, sStats,));
4772 oInstr.sStats = sStats;
4773
4774 _ = iEndLine;
4775 return True;
4776
4777 def parseTagOpDone(self, sTag, aasSections, iTagLine, iEndLine):
4778 """
4779 Tag: @opdone
4780 Value: none
4781
4782 Used to explictily flush the instructions that have been specified.
4783 """
4784 sFlattened = self.flattenAllSections(aasSections);
4785 if sFlattened != '':
4786 return self.errorComment(iTagLine, '%s: takes no value, found: "%s"' % (sTag, sFlattened,));
4787 _ = sTag; _ = iEndLine;
4788 return self.doneInstructions();
4789
4790 ## @}
4791
4792
4793 def parseComment(self):
4794 """
4795 Parse the current comment (self.sComment).
4796
4797 If it's a opcode specifiying comment, we reset the macro stuff.
4798 """
4799 #
4800 # Reject if comment doesn't seem to contain anything interesting.
4801 #
4802 if self.sComment.find('Opcode') < 0 \
4803 and self.sComment.find('@') < 0:
4804 return False;
4805
4806 #
4807 # Split the comment into lines, removing leading asterisks and spaces.
4808 # Also remove leading and trailing empty lines.
4809 #
4810 asLines = self.sComment.split('\n');
4811 for iLine, sLine in enumerate(asLines):
4812 asLines[iLine] = sLine.lstrip().lstrip('*').lstrip();
4813
4814 while asLines and not asLines[0]:
4815 self.iCommentLine += 1;
4816 asLines.pop(0);
4817
4818 while asLines and not asLines[-1]:
4819 asLines.pop(len(asLines) - 1);
4820
4821 #
4822 # Check for old style: Opcode 0x0f 0x12
4823 #
4824 if asLines[0].startswith('Opcode '):
4825 self.parseCommentOldOpcode(asLines);
4826
4827 #
4828 # Look for @op* tagged data.
4829 #
4830 cOpTags = 0;
4831 sFlatDefault = None;
4832 sCurTag = '@default';
4833 iCurTagLine = 0;
4834 asCurSection = [];
4835 aasSections = [ asCurSection, ];
4836 for iLine, sLine in enumerate(asLines):
4837 if not sLine.startswith('@'):
4838 if sLine:
4839 asCurSection.append(sLine);
4840 elif asCurSection:
4841 asCurSection = [];
4842 aasSections.append(asCurSection);
4843 else:
4844 #
4845 # Process the previous tag.
4846 #
4847 if not asCurSection and len(aasSections) > 1:
4848 aasSections.pop(-1);
4849 if sCurTag in self.dTagHandlers:
4850 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
4851 cOpTags += 1;
4852 elif sCurTag.startswith('@op'):
4853 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
4854 elif sCurTag == '@default':
4855 sFlatDefault = self.flattenAllSections(aasSections);
4856 elif '@op' + sCurTag[1:] in self.dTagHandlers:
4857 self.errorComment(iCurTagLine, 'Did you mean "@op%s" rather than "%s"?' % (sCurTag[1:], sCurTag));
4858 elif sCurTag in ['@encoding', '@opencoding']:
4859 self.errorComment(iCurTagLine, 'Did you mean "@openc" rather than "%s"?' % (sCurTag,));
4860
4861 #
4862 # New tag.
4863 #
4864 asSplit = sLine.split(None, 1);
4865 sCurTag = asSplit[0].lower();
4866 if len(asSplit) > 1:
4867 asCurSection = [asSplit[1],];
4868 else:
4869 asCurSection = [];
4870 aasSections = [asCurSection, ];
4871 iCurTagLine = iLine;
4872
4873 #
4874 # Process the final tag.
4875 #
4876 if not asCurSection and len(aasSections) > 1:
4877 aasSections.pop(-1);
4878 if sCurTag in self.dTagHandlers:
4879 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
4880 cOpTags += 1;
4881 elif sCurTag.startswith('@op'):
4882 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
4883 elif sCurTag == '@default':
4884 sFlatDefault = self.flattenAllSections(aasSections);
4885
4886 #
4887 # Don't allow default text in blocks containing @op*.
4888 #
4889 if cOpTags > 0 and sFlatDefault:
4890 self.errorComment(0, 'Untagged comment text is not allowed with @op*: %s' % (sFlatDefault,));
4891
4892 return True;
4893
4894 def parseMacroInvocation(self, sInvocation, offStartInvocation = 0):
4895 """
4896 Parses a macro invocation.
4897
4898 Returns three values:
4899 1. A list of macro arguments, where the zero'th is the macro name.
4900 2. The offset following the macro invocation, into sInvocation of
4901 this is on the same line or into the last line if it is on a
4902 different line.
4903 3. Number of additional lines the invocation spans (i.e. zero if
4904 it is all contained within sInvocation).
4905 """
4906 # First the name.
4907 offOpen = sInvocation.find('(', offStartInvocation);
4908 if offOpen <= offStartInvocation:
4909 self.raiseError("macro invocation open parenthesis not found");
4910 sName = sInvocation[offStartInvocation:offOpen].strip();
4911 if not self.oReMacroName.match(sName):
4912 self.raiseError("invalid macro name '%s'" % (sName,));
4913 asRet = [sName, ];
4914
4915 # Arguments.
4916 iLine = self.iLine;
4917 cDepth = 1;
4918 off = offOpen + 1;
4919 offStart = off;
4920 offCurLn = 0;
4921 chQuote = None;
4922 while cDepth > 0:
4923 if off >= len(sInvocation):
4924 if iLine >= len(self.asLines):
4925 self.error('macro invocation beyond end of file');
4926 return (asRet, off - offCurLn, iLine - self.iLine);
4927 offCurLn = off;
4928 sInvocation += self.asLines[iLine];
4929 iLine += 1;
4930 ch = sInvocation[off];
4931
4932 if chQuote:
4933 if ch == '\\' and off + 1 < len(sInvocation):
4934 off += 1;
4935 elif ch == chQuote:
4936 chQuote = None;
4937 elif ch in ('"', '\'',):
4938 chQuote = ch;
4939 elif ch in (',', ')',):
4940 if cDepth == 1:
4941 asRet.append(sInvocation[offStart:off].strip());
4942 offStart = off + 1;
4943 if ch == ')':
4944 cDepth -= 1;
4945 elif ch == '(':
4946 cDepth += 1;
4947 off += 1;
4948
4949 return (asRet, off - offCurLn, iLine - self.iLine);
4950
4951 def findAndParseMacroInvocationEx(self, sCode, sMacro, offStart = 0):
4952 """
4953 Returns (None, len(sCode), 0) if not found, otherwise the
4954 parseMacroInvocation() return value.
4955 """
4956 offHit = sCode.find(sMacro, offStart);
4957 if offHit >= 0 and sCode[offHit + len(sMacro):].strip()[0] == '(':
4958 return self.parseMacroInvocation(sCode, offHit);
4959 return (None, len(sCode), 0);
4960
4961 def findAndParseMacroInvocation(self, sCode, sMacro):
4962 """
4963 Returns None if not found, arguments as per parseMacroInvocation if found.
4964 """
4965 return self.findAndParseMacroInvocationEx(sCode, sMacro)[0];
4966
4967 def findAndParseFirstMacroInvocation(self, sCode, asMacro):
4968 """
4969 Returns same as findAndParseMacroInvocation.
4970 """
4971 for sMacro in asMacro:
4972 asRet = self.findAndParseMacroInvocation(sCode, sMacro);
4973 if asRet is not None:
4974 return asRet;
4975 return None;
4976
4977 def workerIemOpMnemonicEx(self, sMacro, sStats, sAsm, sForm, sUpper, sLower, # pylint: disable=too-many-arguments
4978 sDisHints, sIemHints, asOperands):
4979 """
4980 Processes one of the a IEMOP_MNEMONIC0EX, IEMOP_MNEMONIC1EX, IEMOP_MNEMONIC2EX,
4981 IEMOP_MNEMONIC3EX, and IEMOP_MNEMONIC4EX macros.
4982 """
4983 #
4984 # Some invocation checks.
4985 #
4986 if sUpper != sUpper.upper():
4987 self.error('%s: bad a_Upper parameter: %s' % (sMacro, sUpper,));
4988 if sLower != sLower.lower():
4989 self.error('%s: bad a_Lower parameter: %s' % (sMacro, sLower,));
4990 if sUpper.lower() != sLower:
4991 self.error('%s: a_Upper and a_Lower parameters does not match: %s vs %s' % (sMacro, sUpper, sLower,));
4992 if not self.oReMnemonic.match(sLower):
4993 self.error('%s: invalid a_Lower: %s (valid: %s)' % (sMacro, sLower, self.oReMnemonic.pattern,));
4994
4995 #
4996 # Check if sIemHints tells us to not consider this macro invocation.
4997 #
4998 if sIemHints.find('IEMOPHINT_SKIP_PYTHON') >= 0:
4999 return True;
5000
5001 # Apply to the last instruction only for now.
5002 if not self.aoCurInstrs:
5003 self.addInstruction();
5004 oInstr = self.aoCurInstrs[-1];
5005 if oInstr.iLineMnemonicMacro == -1:
5006 oInstr.iLineMnemonicMacro = self.iLine;
5007 else:
5008 self.error('%s: already saw a IEMOP_MNEMONIC* macro on line %u for this instruction'
5009 % (sMacro, oInstr.iLineMnemonicMacro,));
5010
5011 # Mnemonic
5012 if oInstr.sMnemonic is None:
5013 oInstr.sMnemonic = sLower;
5014 elif oInstr.sMnemonic != sLower:
5015 self.error('%s: current instruction and a_Lower does not match: %s vs %s' % (sMacro, oInstr.sMnemonic, sLower,));
5016
5017 # Process operands.
5018 if len(oInstr.aoOperands) not in [0, len(asOperands)]:
5019 self.error('%s: number of operands given by @opN does not match macro: %s vs %s'
5020 % (sMacro, len(oInstr.aoOperands), len(asOperands),));
5021 for iOperand, sType in enumerate(asOperands):
5022 sWhere = g_kdOpTypes.get(sType, [None, None])[1];
5023 if sWhere is None:
5024 self.error('%s: unknown a_Op%u value: %s' % (sMacro, iOperand + 1, sType));
5025 if iOperand < len(oInstr.aoOperands): # error recovery.
5026 sWhere = oInstr.aoOperands[iOperand].sWhere;
5027 sType = oInstr.aoOperands[iOperand].sType;
5028 else:
5029 sWhere = 'reg';
5030 sType = 'Gb';
5031 if iOperand == len(oInstr.aoOperands):
5032 oInstr.aoOperands.append(Operand(sWhere, sType))
5033 elif oInstr.aoOperands[iOperand].sWhere != sWhere or oInstr.aoOperands[iOperand].sType != sType:
5034 self.error('%s: @op%u and a_Op%u mismatch: %s:%s vs %s:%s'
5035 % (sMacro, iOperand + 1, iOperand + 1, oInstr.aoOperands[iOperand].sWhere,
5036 oInstr.aoOperands[iOperand].sType, sWhere, sType,));
5037
5038 # Encoding.
5039 if sForm not in g_kdIemForms:
5040 self.error('%s: unknown a_Form value: %s' % (sMacro, sForm,));
5041 else:
5042 if oInstr.sEncoding is None:
5043 oInstr.sEncoding = g_kdIemForms[sForm][0];
5044 elif g_kdIemForms[sForm][0] != oInstr.sEncoding:
5045 self.error('%s: current instruction @openc and a_Form does not match: %s vs %s (%s)'
5046 % (sMacro, oInstr.sEncoding, g_kdIemForms[sForm], sForm));
5047
5048 # Check the parameter locations for the encoding.
5049 if g_kdIemForms[sForm][1] is not None:
5050 if len(g_kdIemForms[sForm][1]) > len(oInstr.aoOperands):
5051 self.error('%s: The a_Form=%s has a different operand count: %s (form) vs %s'
5052 % (sMacro, sForm, len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands) ));
5053 else:
5054 for iOperand, sWhere in enumerate(g_kdIemForms[sForm][1]):
5055 if oInstr.aoOperands[iOperand].sWhere != sWhere:
5056 self.error('%s: current instruction @op%u and a_Form location does not match: %s vs %s (%s)'
5057 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sWhere, sWhere, sForm,));
5058 sOpFormMatch = g_kdOpTypes[oInstr.aoOperands[iOperand].sType][4];
5059 if (sOpFormMatch in [ 'REG', 'MEM', ] and sForm.find('_' + sOpFormMatch) < 0) \
5060 or (sOpFormMatch in [ 'FIXED', ] and sForm.find(sOpFormMatch) < 0) \
5061 or (sOpFormMatch == 'RM' and (sForm.find('_MEM') > 0 or sForm.find('_REG') > 0) ) \
5062 or (sOpFormMatch == 'V' and ( not (sForm.find('VEX') > 0 or sForm.find('XOP')) \
5063 or sForm.replace('VEX','').find('V') < 0) ):
5064 self.error('%s: current instruction @op%u and a_Form type does not match: %s/%s vs %s'
5065 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sType, sOpFormMatch, sForm, ));
5066 if len(g_kdIemForms[sForm][1]) < len(oInstr.aoOperands):
5067 for iOperand in range(len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands)):
5068 if oInstr.aoOperands[iOperand].sType != 'FIXED' \
5069 and g_kdOpTypes[oInstr.aoOperands[iOperand].sType][0] != 'IDX_ParseFixedReg':
5070 self.error('%s: Expected FIXED type operand #%u following operands given by a_Form=%s: %s (%s)'
5071 % (sMacro, iOperand, sForm, oInstr.aoOperands[iOperand].sType,
5072 oInstr.aoOperands[iOperand].sWhere));
5073
5074
5075 # Check @opcodesub
5076 if oInstr.sSubOpcode \
5077 and g_kdIemForms[sForm][2] \
5078 and oInstr.sSubOpcode.find(g_kdIemForms[sForm][2]) < 0:
5079 self.error('%s: current instruction @opcodesub and a_Form does not match: %s vs %s (%s)'
5080 % (sMacro, oInstr.sSubOpcode, g_kdIemForms[sForm][2], sForm,));
5081
5082 # Stats.
5083 if not self.oReStatsName.match(sStats):
5084 self.error('%s: invalid a_Stats value: %s' % (sMacro, sStats,));
5085 elif oInstr.sStats is None:
5086 oInstr.sStats = sStats;
5087 elif oInstr.sStats != sStats:
5088 self.error('%s: mismatching @opstats and a_Stats value: %s vs %s'
5089 % (sMacro, oInstr.sStats, sStats,));
5090
5091 # Process the hints (simply merge with @ophints w/o checking anything).
5092 for sHint in sDisHints.split('|'):
5093 sHint = sHint.strip();
5094 if sHint.startswith('DISOPTYPE_'):
5095 sShortHint = sHint[len('DISOPTYPE_'):].lower();
5096 if sShortHint in g_kdHints:
5097 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5098 else:
5099 self.error('%s: unknown a_fDisHints value: %s' % (sMacro, sHint,));
5100 elif sHint != '0':
5101 self.error('%s: expected a_fDisHints value: %s' % (sMacro, sHint,));
5102
5103 for sHint in sIemHints.split('|'):
5104 sHint = sHint.strip();
5105 if sHint.startswith('IEMOPHINT_'):
5106 sShortHint = sHint[len('IEMOPHINT_'):].lower();
5107 if sShortHint in g_kdHints:
5108 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
5109 else:
5110 self.error('%s: unknown a_fIemHints value: %s' % (sMacro, sHint,));
5111 elif sHint != '0':
5112 self.error('%s: expected a_fIemHints value: %s' % (sMacro, sHint,));
5113
5114 _ = sAsm;
5115 return True;
5116
5117 def workerIemOpMnemonic(self, sMacro, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands):
5118 """
5119 Processes one of the a IEMOP_MNEMONIC0, IEMOP_MNEMONIC1, IEMOP_MNEMONIC2,
5120 IEMOP_MNEMONIC3, and IEMOP_MNEMONIC4 macros.
5121 """
5122 if not asOperands:
5123 return self.workerIemOpMnemonicEx(sMacro, sLower, sLower, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5124 return self.workerIemOpMnemonicEx(sMacro, sLower + '_' + '_'.join(asOperands), sLower + ' ' + ','.join(asOperands),
5125 sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
5126
5127 def workerIemMcBegin(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine):
5128 """
5129 Process a IEM_MC_BEGIN macro invocation.
5130 """
5131 if self.fDebugMc:
5132 self.debug('IEM_MC_BEGIN on %s off %s' % (self.iLine, offBeginStatementInLine,));
5133 #self.debug('%s<eos>' % (sCode,));
5134
5135 # Check preconditions.
5136 if not self.oCurFunction:
5137 self.raiseError('IEM_MC_BEGIN w/o current function (%s)' % (sCode,));
5138 if self.oCurMcBlock:
5139 self.raiseError('IEM_MC_BEGIN before IEM_MC_END. Previous IEM_MC_BEGIN at line %u' % (self.oCurMcBlock.iBeginLine,));
5140
5141 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5142 cchIndent = offBeginStatementInCodeStr;
5143 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5144 if offPrevNewline >= 0:
5145 cchIndent -= offPrevNewline + 1;
5146 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5147
5148 # Start a new block.
5149 # But don't add it to the list unless the context matches the host architecture.
5150 self.oCurMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine,
5151 self.oCurFunction, self.iMcBlockInFunc, cchIndent);
5152 try:
5153 if ( not self.aoCppCondStack
5154 or not self.sHostArch
5155 or self.PreprocessorConditional.isInBlockForArch(self.aoCppCondStack, self.sHostArch, self.iLine)):
5156 g_aoMcBlocks.append(self.oCurMcBlock);
5157 self.cTotalMcBlocks += 1;
5158 except Exception as oXcpt:
5159 self.raiseError(oXcpt.args[0]);
5160
5161 self.iMcBlockInFunc += 1;
5162 return True;
5163
5164 @staticmethod
5165 def extractLinesFromMacroExpansionLine(sRawLine, offBegin, offEnd, sBeginStmt = 'IEM_MC_BEGIN'):
5166 """
5167 Helper used by workerIemMcEnd and workerIemMcDeferToCImplXRet for
5168 extracting a statement block from a string that's the result of macro
5169 expansion and therefore contains multiple "sub-lines" as it were.
5170
5171 Returns list of lines covering offBegin thru offEnd in sRawLine.
5172 """
5173
5174 off = sRawLine.find('\n', offEnd);
5175 if off > 0:
5176 sRawLine = sRawLine[:off + 1];
5177
5178 off = sRawLine.rfind('\n', 0, offBegin) + 1;
5179 sRawLine = sRawLine[off:];
5180 if not sRawLine.strip().startswith(sBeginStmt):
5181 sRawLine = sRawLine[offBegin - off:]
5182
5183 return [sLine + '\n' for sLine in sRawLine.split('\n')];
5184
5185 def workerIemMcEnd(self, offEndStatementInLine):
5186 """
5187 Process a IEM_MC_END macro invocation.
5188 """
5189 if self.fDebugMc:
5190 self.debug('IEM_MC_END on %s off %s' % (self.iLine, offEndStatementInLine,));
5191
5192 # Check preconditions.
5193 if not self.oCurMcBlock:
5194 self.raiseError('IEM_MC_END w/o IEM_MC_BEGIN.');
5195
5196 #
5197 # HACK ALERT! For blocks originating from macro expansion the start and
5198 # end line will be the same, but the line has multiple
5199 # newlines inside it. So, we have to do some extra tricks
5200 # to get the lines out of there. We ASSUME macros aren't
5201 # messy, but keep IEM_MC_BEGIN/END on separate lines.
5202 #
5203 if self.iLine > self.oCurMcBlock.iBeginLine:
5204 asLines = self.asLines[self.oCurMcBlock.iBeginLine - 1 : self.iLine];
5205 if not asLines[0].strip().startswith('IEM_MC_BEGIN'):
5206 self.raiseError('IEM_MC_BEGIN is not the first word on the line');
5207
5208 # Hack alert! Detect mixed tail/head macros a la cmpxchg16b and split up the lines
5209 # so we can deal correctly with IEM_MC_END below and everything else.
5210 for sLine in asLines:
5211 cNewLines = sLine.count('\n');
5212 assert cNewLines > 0;
5213 if cNewLines > 1:
5214 asLines = self.extractLinesFromMacroExpansionLine(''.join(asLines),
5215 self.oCurMcBlock.offBeginLine,
5216 offEndStatementInLine
5217 + sum(len(s) for s in asLines)
5218 - len(asLines[-1]));
5219 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Partial;
5220 break;
5221 else:
5222 self.oCurMcBlock.iMacroExp = McBlock.kiMacroExp_Entire;
5223 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1],
5224 self.oCurMcBlock.offBeginLine, offEndStatementInLine);
5225
5226 #
5227 # Strip anything following the IEM_MC_END(); statement in the final line,
5228 # so that we don't carry on any trailing 'break' after macro expansions
5229 # like for iemOp_movsb_Xb_Yb.
5230 #
5231 while asLines[-1].strip() == '':
5232 asLines.pop();
5233 sFinal = asLines[-1];
5234 offFinalEnd = sFinal.find('IEM_MC_END');
5235 offEndInFinal = offFinalEnd;
5236 if offFinalEnd < 0: self.raiseError('bogus IEM_MC_END: Not in final line: %s' % (sFinal,));
5237 offFinalEnd += len('IEM_MC_END');
5238
5239 while sFinal[offFinalEnd].isspace():
5240 offFinalEnd += 1;
5241 if sFinal[offFinalEnd] != '(': self.raiseError('bogus IEM_MC_END: Expected "(" at %s: %s' % (offFinalEnd, sFinal,));
5242 offFinalEnd += 1;
5243
5244 while sFinal[offFinalEnd].isspace():
5245 offFinalEnd += 1;
5246 if sFinal[offFinalEnd] != ')': self.raiseError('bogus IEM_MC_END: Expected ")" at %s: %s' % (offFinalEnd, sFinal,));
5247 offFinalEnd += 1;
5248
5249 while sFinal[offFinalEnd].isspace():
5250 offFinalEnd += 1;
5251 if sFinal[offFinalEnd] != ';': self.raiseError('bogus IEM_MC_END: Expected ";" at %s: %s' % (offFinalEnd, sFinal,));
5252 offFinalEnd += 1;
5253
5254 asLines[-1] = sFinal[: offFinalEnd];
5255
5256 #
5257 # Complete and discard the current block.
5258 #
5259 self.oCurMcBlock.complete(self.iLine, offEndStatementInLine,
5260 offEndStatementInLine + offFinalEnd - offEndInFinal, asLines);
5261 self.oCurMcBlock = None;
5262 return True;
5263
5264 def workerIemMcDeferToCImplXRet(self, sCode, offBeginStatementInCodeStr, offBeginStatementInLine, cParams):
5265 """
5266 Process a IEM_MC_DEFER_TO_CIMPL_[1-5]_RET macro invocation.
5267 """
5268 sStmt = 'IEM_MC_DEFER_TO_CIMPL_%d_RET' % (cParams,);
5269 if self.fDebugMc:
5270 self.debug('%s on %s off %s' % (sStmt, self.iLine, offBeginStatementInLine,));
5271 #self.debug('%s<eos>' % (sCode,));
5272
5273 # Check preconditions.
5274 if not self.oCurFunction:
5275 self.raiseError('%s w/o current function (%s)' % (sStmt, sCode,));
5276 if self.oCurMcBlock:
5277 self.raiseError('%s inside IEM_MC_BEGIN blocki starting at line %u' % (sStmt, self.oCurMcBlock.iBeginLine,));
5278
5279 # Figure out the indent level the block starts at, adjusting for expanded multiline macros.
5280 cchIndent = offBeginStatementInCodeStr;
5281 offPrevNewline = sCode.rfind('\n', 0, offBeginStatementInCodeStr);
5282 if offPrevNewline >= 0:
5283 cchIndent -= offPrevNewline + 1;
5284 #self.debug('cchIndent=%s offPrevNewline=%s sFunc=%s' % (cchIndent, offPrevNewline, self.oCurFunction.sName));
5285
5286 # Start a new block.
5287 oMcBlock = McBlock(self.sSrcFile, self.iLine, offBeginStatementInLine,
5288 self.oCurFunction, self.iMcBlockInFunc, cchIndent, fDeferToCImpl = True);
5289
5290 # Parse the statment.
5291 asArgs, offAfter, cLines = self.findAndParseMacroInvocationEx(sCode, sStmt, offBeginStatementInCodeStr);
5292 if asArgs is None:
5293 self.raiseError('%s: Closing parenthesis not found!' % (sStmt,));
5294 if len(asArgs) != cParams + 4:
5295 self.raiseError('%s: findAndParseMacroInvocationEx returns %s args, expected %s! (%s)'
5296 % (sStmt, len(asArgs), cParams + 4, asArgs));
5297
5298 oMcBlock.aoStmts = [ McBlock.parseMcDeferToCImpl(oMcBlock, asArgs[0], asArgs[1:]), ];
5299
5300 # These MCs are not typically part of macro expansions, but let's get
5301 # it out of the way immediately if it's the case.
5302 if cLines > 0 or self.asLines[oMcBlock.iBeginLine - 1].count('\n') <= 1:
5303 asLines = self.asLines[self.iLine - 1 : self.iLine - 1 + cLines + 1];
5304 assert offAfter < len(asLines[-1]) and asLines[-1][offAfter] == ';', \
5305 'iBeginLine=%d iLine=%d offAfter=%s line: "%s"' % (oMcBlock.iBeginLine, self.iLine, offAfter, asLines[-1],);
5306 asLines[-1] = asLines[-1][:offAfter + 1];
5307 else:
5308 asLines = self.extractLinesFromMacroExpansionLine(self.asLines[self.iLine - 1], offBeginStatementInCodeStr,
5309 offAfter, sStmt);
5310 assert asLines[-1].find(';') >= 0;
5311 asLines[-1] = asLines[-1][:asLines[-1].find(';') + 1];
5312
5313 assert asLines[0].find(sStmt) >= 0;
5314 #if not asLines[0].strip().startswith(sStmt):
5315 # self.raiseError('%s is not the first word on the line: %s' % (sStmt, asLines[0].strip()));
5316
5317 # Advance to the line with the closing ')'.
5318 self.iLine += cLines;
5319
5320 # Complete the block.
5321 oMcBlock.complete(self.iLine, 0 if cLines > 0 else offBeginStatementInCodeStr, offAfter + 1, asLines);
5322
5323 g_aoMcBlocks.append(oMcBlock);
5324 self.cTotalMcBlocks += 1;
5325 self.iMcBlockInFunc += 1;
5326
5327 return True;
5328
5329 def workerStartFunction(self, asArgs):
5330 """
5331 Deals with the start of a decoder function.
5332
5333 These are all defined using one of the FNIEMOP*_DEF* and FNIEMOP_*STUB*
5334 macros, so we get a argument list for these where the 0th argument is the
5335 macro name.
5336 """
5337 # Complete any existing function.
5338 if self.oCurFunction:
5339 self.oCurFunction.complete(self.iLine - 1, self.asLines[self.oCurFunction.iBeginLine - 1 : self.iLine - 1]);
5340
5341 # Create the new function.
5342 self.oCurFunction = DecoderFunction(self.sSrcFile, self.iLine, asArgs[1], asArgs);
5343 return True;
5344
5345 def checkCodeForMacro(self, sCode, offLine):
5346 """
5347 Checks code for relevant macro invocation.
5348 """
5349
5350 #
5351 # Scan macro invocations.
5352 #
5353 if sCode.find('(') > 0:
5354 # Look for instruction decoder function definitions. ASSUME single line.
5355 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5356 [ 'FNIEMOP_DEF',
5357 'FNIEMOPRM_DEF',
5358 'FNIEMOP_STUB',
5359 'FNIEMOP_STUB_1',
5360 'FNIEMOP_UD_STUB',
5361 'FNIEMOP_UD_STUB_1' ]);
5362 if asArgs is not None:
5363 self.workerStartFunction(asArgs);
5364 #self.debug('%s: oCurFunction=%s' % (self.iLine, self.oCurFunction.sName,));
5365
5366 if not self.aoCurInstrs:
5367 self.addInstruction();
5368 for oInstr in self.aoCurInstrs:
5369 if oInstr.iLineFnIemOpMacro == -1:
5370 oInstr.iLineFnIemOpMacro = self.iLine;
5371 else:
5372 self.error('%s: already seen a FNIEMOP_XXX macro for %s' % (asArgs[0], oInstr,) );
5373 self.setInstrunctionAttrib('sFunction', asArgs[1]);
5374 self.setInstrunctionAttrib('fStub', asArgs[0].find('STUB') > 0, fOverwrite = True);
5375 self.setInstrunctionAttrib('fUdStub', asArgs[0].find('UD_STUB') > 0, fOverwrite = True);
5376 if asArgs[0].find('STUB') > 0:
5377 self.doneInstructions(fEndOfFunction = True);
5378 return True;
5379
5380 # Check for worker function definitions, so we can get a context for MC blocks.
5381 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5382 [ 'FNIEMOP_DEF_1',
5383 'FNIEMOP_DEF_2', ]);
5384 if asArgs is not None:
5385 self.workerStartFunction(asArgs);
5386 #self.debug('%s: oCurFunction=%s (%s)' % (self.iLine, self.oCurFunction.sName, asArgs[0]));
5387 return True;
5388
5389 # IEMOP_HLP_DONE_VEX_DECODING_*
5390 asArgs = self.findAndParseFirstMacroInvocation(sCode,
5391 [ 'IEMOP_HLP_DONE_VEX_DECODING',
5392 'IEMOP_HLP_DONE_VEX_DECODING_L0',
5393 'IEMOP_HLP_DONE_VEX_DECODING_NO_VVVV',
5394 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV',
5395 ]);
5396 if asArgs is not None:
5397 sMacro = asArgs[0];
5398 if sMacro in ('IEMOP_HLP_DONE_VEX_DECODING_L0', 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV', ):
5399 for oInstr in self.aoCurInstrs:
5400 if 'vex_l_zero' not in oInstr.dHints:
5401 if oInstr.iLineMnemonicMacro >= 0:
5402 self.errorOnLine(oInstr.iLineMnemonicMacro,
5403 'Missing IEMOPHINT_VEX_L_ZERO! (%s on line %d)' % (sMacro, self.iLine,));
5404 oInstr.dHints['vex_l_zero'] = True;
5405
5406 #
5407 # IEMOP_MNEMONIC*
5408 #
5409 if sCode.find('IEMOP_MNEMONIC') >= 0:
5410 # IEMOP_MNEMONIC(a_Stats, a_szMnemonic) IEMOP_INC_STATS(a_Stats)
5411 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC');
5412 if asArgs is not None:
5413 if len(self.aoCurInstrs) == 1:
5414 oInstr = self.aoCurInstrs[0];
5415 if oInstr.sStats is None:
5416 oInstr.sStats = asArgs[1];
5417 self.deriveMnemonicAndOperandsFromStats(oInstr, asArgs[1]);
5418
5419 # IEMOP_MNEMONIC0EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5420 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0EX');
5421 if asArgs is not None:
5422 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[6],
5423 asArgs[7], []);
5424 # IEMOP_MNEMONIC1EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5425 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1EX');
5426 if asArgs is not None:
5427 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[7],
5428 asArgs[8], [asArgs[6],]);
5429 # IEMOP_MNEMONIC2EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5430 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2EX');
5431 if asArgs is not None:
5432 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[8],
5433 asArgs[9], [asArgs[6], asArgs[7]]);
5434 # IEMOP_MNEMONIC3EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints,
5435 # a_fIemHints)
5436 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3EX');
5437 if asArgs is not None:
5438 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[9],
5439 asArgs[10], [asArgs[6], asArgs[7], asArgs[8],]);
5440 # IEMOP_MNEMONIC4EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints,
5441 # a_fIemHints)
5442 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4EX');
5443 if asArgs is not None:
5444 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[10],
5445 asArgs[11], [asArgs[6], asArgs[7], asArgs[8], asArgs[9],]);
5446
5447 # IEMOP_MNEMONIC0(a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
5448 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0');
5449 if asArgs is not None:
5450 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], []);
5451 # IEMOP_MNEMONIC1(a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
5452 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1');
5453 if asArgs is not None:
5454 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[5], asArgs[6], [asArgs[4],]);
5455 # IEMOP_MNEMONIC2(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
5456 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2');
5457 if asArgs is not None:
5458 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[6], asArgs[7],
5459 [asArgs[4], asArgs[5],]);
5460 # IEMOP_MNEMONIC3(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints, a_fIemHints)
5461 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3');
5462 if asArgs is not None:
5463 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[7], asArgs[8],
5464 [asArgs[4], asArgs[5], asArgs[6],]);
5465 # IEMOP_MNEMONIC4(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints, a_fIemHints)
5466 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4');
5467 if asArgs is not None:
5468 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[8], asArgs[9],
5469 [asArgs[4], asArgs[5], asArgs[6], asArgs[7],]);
5470
5471 #
5472 # IEM_MC_BEGIN + IEM_MC_END.
5473 # We must support multiple instances per code snippet.
5474 #
5475 offCode = sCode.find('IEM_MC_');
5476 if offCode >= 0:
5477 for oMatch in self.oReMcBeginEnd.finditer(sCode, offCode):
5478 if oMatch.group(1) == 'END':
5479 self.workerIemMcEnd(offLine + oMatch.start());
5480 elif oMatch.group(1) == 'BEGIN':
5481 self.workerIemMcBegin(sCode, oMatch.start(), offLine + oMatch.start());
5482 else:
5483 self.workerIemMcDeferToCImplXRet(sCode, oMatch.start(), offLine + oMatch.start(),
5484 int(oMatch.group(1)[len('DEFER_TO_CIMPL_')]));
5485 return True;
5486
5487 return False;
5488
5489 def workerPreprocessorRecreateMacroRegex(self):
5490 """
5491 Recreates self.oReMacros when self.dMacros changes.
5492 """
5493 if self.dMacros:
5494 sRegex = '';
5495 for sName, oMacro in self.dMacros.items():
5496 if sRegex:
5497 sRegex += r'|' + sName;
5498 else:
5499 sRegex = r'\b(' + sName;
5500 if oMacro.asArgs is not None:
5501 sRegex += r'\s*\(';
5502 else:
5503 sRegex += r'\b';
5504 sRegex += ')';
5505 self.oReMacros = re.compile(sRegex);
5506 else:
5507 self.oReMacros = None;
5508 return True;
5509
5510 def workerPreprocessorDefine(self, sRest):
5511 """
5512 Handles a macro #define, the sRest is what follows after the directive word.
5513 """
5514 assert sRest[-1] == '\n';
5515
5516 #
5517 # If using line continutation, just concat all the lines together,
5518 # preserving the newline character but not the escaping.
5519 #
5520 iLineStart = self.iLine;
5521 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
5522 sRest = sRest[0:-2].rstrip() + '\n' + self.asLines[self.iLine];
5523 self.iLine += 1;
5524 #self.debug('workerPreprocessorDefine: sRest=%s<EOS>' % (sRest,));
5525
5526 #
5527 # Use regex to split out the name, argument list and body.
5528 # If this fails, we assume it's a simple macro.
5529 #
5530 oMatch = self.oReHashDefine2.match(sRest);
5531 if oMatch:
5532 sAllArgs = oMatch.group(2).strip();
5533 asArgs = [sParam.strip() for sParam in sAllArgs.split(',')] if sAllArgs else None;
5534 sBody = oMatch.group(3);
5535 else:
5536 oMatch = self.oReHashDefine3.match(sRest);
5537 if not oMatch:
5538 self.debug('workerPreprocessorDefine: wtf? sRest=%s' % (sRest,));
5539 return self.error('bogus macro definition: %s' % (sRest,));
5540 asArgs = None;
5541 sBody = oMatch.group(2);
5542 sName = oMatch.group(1);
5543 assert sName == sName.strip();
5544 #self.debug('workerPreprocessorDefine: sName=%s asArgs=%s sBody=%s<EOS>' % (sName, asArgs, sBody));
5545
5546 #
5547 # Is this of any interest to us? We do NOT support MC blocks wihtin
5548 # nested macro expansion, just to avoid lots of extra work.
5549 #
5550 # There is only limited support for macros expanding to partial MC blocks.
5551 #
5552 # Note! IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX and other macros someone making
5553 # use of IEMOP_RAISE_INVALID_LOCK_PREFIX_RET() will be ignored here and
5554 # dealt with by overriding IEMOP_RAISE_INVALID_LOCK_PREFIX_RET and its
5555 # siblings in the recompiler. This is a lot simpler than nested macro
5556 # expansion and lots of heuristics for locating all the relevant macros.
5557 # Also, this way we don't produce lots of unnecessary threaded functions.
5558 #
5559 if sBody.find("IEM_MC_BEGIN") < 0 and sBody.find("IEM_MC_END") < 0:
5560 #self.debug('workerPreprocessorDefine: irrelevant (%s: %s)' % (sName, sBody));
5561 return True;
5562
5563 #
5564 # Add the macro.
5565 #
5566 if self.fDebugPreproc:
5567 self.debug('#define %s on line %u' % (sName, self.iLine,));
5568 self.dMacros[sName] = SimpleParser.Macro(sName, asArgs, sBody.strip(), iLineStart);
5569 return self.workerPreprocessorRecreateMacroRegex();
5570
5571 def workerPreprocessorUndef(self, sRest):
5572 """
5573 Handles a macro #undef, the sRest is what follows after the directive word.
5574 """
5575 # Quick comment strip and isolate the name.
5576 offSlash = sRest.find('/');
5577 if offSlash > 0:
5578 sRest = sRest[:offSlash];
5579 sName = sRest.strip();
5580
5581 # Remove the macro if we're clocking it.
5582 if sName in self.dMacros:
5583 if self.fDebugPreproc:
5584 self.debug('#undef %s on line %u' % (sName, self.iLine,));
5585 del self.dMacros[sName];
5586 return self.workerPreprocessorRecreateMacroRegex();
5587
5588 return True;
5589
5590 def workerPreprocessorIfOrElif(self, sDirective, sRest):
5591 """
5592 Handles an #if, #ifdef, #ifndef or #elif directive.
5593 """
5594 #
5595 # Sanity check #elif.
5596 #
5597 if sDirective == 'elif':
5598 if len(self.aoCppCondStack) == 0:
5599 self.raiseError('#elif without #if');
5600 if self.aoCppCondStack[-1].fInElse:
5601 self.raiseError('#elif after #else');
5602
5603 #
5604 # If using line continutation, just concat all the lines together,
5605 # stripping both the newline and escape characters.
5606 #
5607 while sRest.endswith('\\\n') and self.iLine < len(self.asLines):
5608 sRest = sRest[0:-2].rstrip() + ' ' + self.asLines[self.iLine];
5609 self.iLine += 1;
5610
5611 # Strip it of all comments and leading and trailing blanks.
5612 sRest = self.stripComments(sRest).strip();
5613
5614 #
5615 # Stash it.
5616 #
5617 try:
5618 oPreprocCond = self.PreprocessorConditional(sDirective, sRest);
5619 except Exception as oXcpt:
5620 self.raiseError(oXcpt.args[0]);
5621
5622 if sDirective == 'elif':
5623 self.aoCppCondStack[-1].aoElif.append(oPreprocCond);
5624 else:
5625 self.aoCppCondStack.append(oPreprocCond);
5626
5627 return True;
5628
5629 def workerPreprocessorElse(self):
5630 """
5631 Handles an #else directive.
5632 """
5633 if len(self.aoCppCondStack) == 0:
5634 self.raiseError('#else without #if');
5635 if self.aoCppCondStack[-1].fInElse:
5636 self.raiseError('Another #else after #else');
5637
5638 self.aoCppCondStack[-1].fInElse = True;
5639 return True;
5640
5641 def workerPreprocessorEndif(self):
5642 """
5643 Handles an #endif directive.
5644 """
5645 if len(self.aoCppCondStack) == 0:
5646 self.raiseError('#endif without #if');
5647
5648 self.aoCppCondStack.pop();
5649 return True;
5650
5651 def checkPreprocessorDirective(self, sLine):
5652 """
5653 Handles a preprocessor directive.
5654 """
5655 # Skip past the preprocessor hash.
5656 off = sLine.find('#');
5657 assert off >= 0;
5658 off += 1;
5659 while off < len(sLine) and sLine[off].isspace():
5660 off += 1;
5661
5662 # Extract the directive.
5663 offDirective = off;
5664 while off < len(sLine) and not sLine[off].isspace():
5665 off += 1;
5666 sDirective = sLine[offDirective:off];
5667 if self.fDebugPreproc:
5668 self.debug('line %d: #%s...' % (self.iLine, sDirective));
5669
5670 # Skip spaces following it to where the arguments/whatever starts.
5671 while off + 1 < len(sLine) and sLine[off + 1].isspace():
5672 off += 1;
5673 sTail = sLine[off:];
5674
5675 # Handle the directive.
5676 if sDirective == 'define':
5677 return self.workerPreprocessorDefine(sTail);
5678 if sDirective == 'undef':
5679 return self.workerPreprocessorUndef(sTail);
5680 if sDirective in ('if', 'ifdef', 'ifndef', 'elif',):
5681 return self.workerPreprocessorIfOrElif(sDirective, sTail);
5682 if sDirective == 'else':
5683 return self.workerPreprocessorElse();
5684 if sDirective == 'endif':
5685 return self.workerPreprocessorEndif();
5686
5687 if self.fDebugPreproc:
5688 self.debug('line %d: Unknown preprocessor directive: %s' % (self.iLine, sDirective));
5689 return False;
5690
5691 def expandMacros(self, sLine, oMatch):
5692 """
5693 Expands macros we know about in the given line.
5694 Currently we ASSUME there is only one and that is what oMatch matched.
5695 """
5696 #
5697 # Get our bearings.
5698 #
5699 offMatch = oMatch.start();
5700 sName = oMatch.group(1);
5701 assert sName == sLine[oMatch.start() : oMatch.end()];
5702 fWithArgs = sName.endswith('(');
5703 if fWithArgs:
5704 sName = sName[:-1].strip();
5705 oMacro = self.dMacros[sName] # type: SimpleParser.Macro
5706
5707 #
5708 # Deal with simple macro invocations w/o parameters.
5709 #
5710 if not fWithArgs:
5711 if self.fDebugPreproc:
5712 self.debug('expanding simple macro %s on line %u' % (sName, self.iLine,));
5713 return sLine[:offMatch] + oMacro.expandMacro(self) + sLine[oMatch.end():];
5714
5715 #
5716 # Complicated macro with parameters.
5717 # Start by extracting the parameters. ASSUMES they are all on the same line!
5718 #
5719 cLevel = 1;
5720 offCur = oMatch.end();
5721 offCurArg = offCur;
5722 asArgs = [];
5723 while True:
5724 if offCur >= len(sLine):
5725 self.raiseError('expandMacros: Invocation of macro %s spans multiple lines!' % (sName,));
5726 ch = sLine[offCur];
5727 if ch == '(':
5728 cLevel += 1;
5729 elif ch == ')':
5730 cLevel -= 1;
5731 if cLevel == 0:
5732 asArgs.append(sLine[offCurArg:offCur].strip());
5733 break;
5734 elif ch == ',' and cLevel == 1:
5735 asArgs.append(sLine[offCurArg:offCur].strip());
5736 offCurArg = offCur + 1;
5737 offCur += 1;
5738 if len(oMacro.asArgs) == 0 and len(asArgs) == 1 and asArgs[0] == '': # trick for empty parameter list.
5739 asArgs = [];
5740 if len(oMacro.asArgs) != len(asArgs):
5741 self.raiseError('expandMacros: Argument mismatch in %s invocation' % (oMacro.sName,));
5742
5743 #
5744 # Do the expanding.
5745 #
5746 if self.fDebugPreproc:
5747 self.debug('expanding macro %s on line %u with arguments %s' % (sName, self.iLine, asArgs));
5748 return sLine[:offMatch] + oMacro.expandMacro(self, asArgs) + sLine[offCur + 1 :];
5749
5750 def parse(self):
5751 """
5752 Parses the given file.
5753
5754 Returns number or errors.
5755 Raises exception on fatal trouble.
5756 """
5757 #self.debug('Parsing %s' % (self.sSrcFile,));
5758
5759 #
5760 # Loop thru the lines.
5761 #
5762 # Please mind that self.iLine may be updated by checkCodeForMacro and
5763 # other worker methods.
5764 #
5765 while self.iLine < len(self.asLines):
5766 sLine = self.asLines[self.iLine];
5767 self.iLine += 1;
5768 #self.debug('line %u: %s' % (self.iLine, sLine[:-1]));
5769
5770 # Expand macros we know about if we're currently in code.
5771 if self.iState == self.kiCode and self.oReMacros:
5772 oMatch = self.oReMacros.search(sLine);
5773 if oMatch:
5774 sLine = self.expandMacros(sLine, oMatch);
5775 if self.fDebugPreproc:
5776 self.debug('line %d: expanded\n%s ==>\n%s' % (self.iLine, self.asLines[self.iLine - 1], sLine[:-1],));
5777 self.asLines[self.iLine - 1] = sLine;
5778
5779 # Check for preprocessor directives before comments and other stuff.
5780 # ASSUMES preprocessor directives doesn't end with multiline comments.
5781 if self.iState == self.kiCode and sLine.lstrip().startswith('#'):
5782 if self.fDebugPreproc:
5783 self.debug('line %d: preproc' % (self.iLine,));
5784 self.checkPreprocessorDirective(sLine);
5785 else:
5786 # Look for comments.
5787 offSlash = sLine.find('/');
5788 if offSlash >= 0:
5789 if offSlash + 1 >= len(sLine) or sLine[offSlash + 1] != '/' or self.iState != self.kiCode:
5790 offLine = 0;
5791 while offLine < len(sLine):
5792 if self.iState == self.kiCode:
5793 # Look for substantial multiline comment so we pass the following MC as a whole line:
5794 # IEM_MC_ARG_CONST(uint8_t, bImmArg, /*=*/ bImm, 2);
5795 # Note! We ignore C++ comments here, assuming these aren't used in lines with C-style comments.
5796 offHit = sLine.find('/*', offLine);
5797 while offHit >= 0:
5798 offEnd = sLine.find('*/', offHit + 2);
5799 if offEnd < 0 or offEnd - offHit >= 16: # 16 chars is a bit random.
5800 break;
5801 offHit = sLine.find('/*', offEnd);
5802
5803 if offHit >= 0:
5804 self.checkCodeForMacro(sLine[offLine:offHit], offLine);
5805 self.sComment = '';
5806 self.iCommentLine = self.iLine;
5807 self.iState = self.kiCommentMulti;
5808 offLine = offHit + 2;
5809 else:
5810 self.checkCodeForMacro(sLine[offLine:], offLine);
5811 offLine = len(sLine);
5812
5813 elif self.iState == self.kiCommentMulti:
5814 offHit = sLine.find('*/', offLine);
5815 if offHit >= 0:
5816 self.sComment += sLine[offLine:offHit];
5817 self.iState = self.kiCode;
5818 offLine = offHit + 2;
5819 self.parseComment();
5820 else:
5821 self.sComment += sLine[offLine:];
5822 offLine = len(sLine);
5823 else:
5824 assert False;
5825 # C++ line comment.
5826 elif offSlash > 0:
5827 self.checkCodeForMacro(sLine[:offSlash], 0);
5828
5829 # No slash, but append the line if in multi-line comment.
5830 elif self.iState == self.kiCommentMulti:
5831 #self.debug('line %d: multi' % (self.iLine,));
5832 self.sComment += sLine;
5833
5834 # No slash, but check code line for relevant macro.
5835 elif ( self.iState == self.kiCode
5836 and (sLine.find('IEMOP_') >= 0 or sLine.find('FNIEMOPRM_DEF') >= 0 or sLine.find('IEM_MC') >= 0)):
5837 #self.debug('line %d: macro' % (self.iLine,));
5838 self.checkCodeForMacro(sLine, 0);
5839
5840 # If the line is a '}' in the first position, complete the instructions.
5841 elif self.iState == self.kiCode and sLine[0] == '}':
5842 #self.debug('line %d: }' % (self.iLine,));
5843 self.doneInstructions(fEndOfFunction = True);
5844
5845 # Look for instruction table on the form 'IEM_STATIC const PFNIEMOP g_apfnVexMap3'
5846 # so we can check/add @oppfx info from it.
5847 elif self.iState == self.kiCode and sLine.find('PFNIEMOP') > 0 and self.oReFunTable.match(sLine):
5848 self.parseFunctionTable(sLine);
5849
5850 self.doneInstructions(fEndOfFunction = True);
5851 self.debug('%3s%% / %3s stubs out of %4s instructions and %4s MC blocks in %s'
5852 % (self.cTotalStubs * 100 // max(self.cTotalInstr, 1), self.cTotalStubs, self.cTotalInstr,
5853 self.cTotalMcBlocks, os.path.basename(self.sSrcFile),));
5854 return self.printErrors();
5855
5856## The parsed content of IEMAllInstCommonBodyMacros.h.
5857g_oParsedCommonBodyMacros = None # type: SimpleParser
5858
5859def __parseFileByName(sSrcFile, sDefaultMap, sHostArch):
5860 """
5861 Parses one source file for instruction specfications.
5862 """
5863 #
5864 # Read sSrcFile into a line array.
5865 #
5866 try:
5867 oFile = open(sSrcFile, "r"); # pylint: disable=consider-using-with,unspecified-encoding
5868 except Exception as oXcpt:
5869 raise Exception("failed to open %s for reading: %s" % (sSrcFile, oXcpt,));
5870 try:
5871 asLines = oFile.readlines();
5872 except Exception as oXcpt:
5873 raise Exception("failed to read %s: %s" % (sSrcFile, oXcpt,));
5874 finally:
5875 oFile.close();
5876
5877 #
5878 # On the first call, we parse IEMAllInstCommonBodyMacros.h so we
5879 # can use the macros from it when processing the other files.
5880 #
5881 global g_oParsedCommonBodyMacros;
5882 if g_oParsedCommonBodyMacros is None:
5883 # Locate the file.
5884 sCommonBodyMacros = os.path.join(os.path.split(sSrcFile)[0], 'IEMAllInstCommonBodyMacros.h');
5885 if not os.path.isfile(sCommonBodyMacros):
5886 sCommonBodyMacros = os.path.join(os.path.split(__file__)[0], 'IEMAllInstCommonBodyMacros.h');
5887
5888 # Read it.
5889 try:
5890 with open(sCommonBodyMacros, "r") as oIncFile: # pylint: disable=unspecified-encoding
5891 asIncFiles = oIncFile.readlines();
5892 except Exception as oXcpt:
5893 raise Exception("failed to open/read %s: %s" % (sCommonBodyMacros, oXcpt,));
5894
5895 # Parse it.
5896 try:
5897 oParser = SimpleParser(sCommonBodyMacros, asIncFiles, 'one', sHostArch);
5898 if oParser.parse() != 0:
5899 raise ParserException('%s: errors: See above' % (sCommonBodyMacros, ));
5900 if oParser.cTotalInstr != 0 or oParser.cTotalStubs != 0 or oParser.cTotalTagged != 0 or oParser.cTotalMcBlocks != 0:
5901 raise ParserException('%s: error: Unexpectedly found %u instr, %u tags, %u stubs and %u MCs, expecting zero. %s'
5902 % (sCommonBodyMacros, oParser.cTotalInstr, oParser.cTotalStubs, oParser.cTotalTagged,
5903 oParser.cTotalMcBlocks,
5904 ', '.join(sorted( [str(oMcBlock.iBeginLine) for oMcBlock in g_aoMcBlocks]
5905 + [str(oInstr.iLineCreated) for oInstr in g_aoAllInstructions])),));
5906 except ParserException as oXcpt:
5907 print(str(oXcpt), file = sys.stderr);
5908 raise;
5909 g_oParsedCommonBodyMacros = oParser;
5910
5911 #
5912 # Do the parsing.
5913 #
5914 try:
5915 oParser = SimpleParser(sSrcFile, asLines, sDefaultMap, sHostArch, g_oParsedCommonBodyMacros);
5916 return (oParser.parse(), oParser) ;
5917 except ParserException as oXcpt:
5918 print(str(oXcpt), file = sys.stderr);
5919 raise;
5920
5921
5922def __doTestCopying():
5923 """
5924 Executes the asCopyTests instructions.
5925 """
5926 asErrors = [];
5927 for oDstInstr in g_aoAllInstructions:
5928 if oDstInstr.asCopyTests:
5929 for sSrcInstr in oDstInstr.asCopyTests:
5930 oSrcInstr = g_dAllInstructionsByStat.get(sSrcInstr, None);
5931 if oSrcInstr:
5932 aoSrcInstrs = [oSrcInstr,];
5933 else:
5934 aoSrcInstrs = g_dAllInstructionsByFunction.get(sSrcInstr, []);
5935 if aoSrcInstrs:
5936 for oSrcInstr in aoSrcInstrs:
5937 if oSrcInstr != oDstInstr:
5938 oDstInstr.aoTests.extend(oSrcInstr.aoTests);
5939 else:
5940 asErrors.append('%s:%s: error: @opcopytests reference "%s" matches the destination\n'
5941 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
5942 else:
5943 asErrors.append('%s:%s: error: @opcopytests reference "%s" not found\n'
5944 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
5945
5946 if asErrors:
5947 sys.stderr.write(u''.join(asErrors));
5948 return len(asErrors);
5949
5950
5951def __applyOnlyTest():
5952 """
5953 If g_aoOnlyTestInstructions contains any instructions, drop aoTests from
5954 all other instructions so that only these get tested.
5955 """
5956 if g_aoOnlyTestInstructions:
5957 for oInstr in g_aoAllInstructions:
5958 if oInstr.aoTests:
5959 if oInstr not in g_aoOnlyTestInstructions:
5960 oInstr.aoTests = [];
5961 return 0;
5962
5963## List of all main instruction files, their default maps and file sets (-1 means included it all sets).
5964g_aaoAllInstrFilesAndDefaultMapAndSet = (
5965 ( 'IEMAllInstCommon.cpp.h', 'one', -1, ),
5966 ( 'IEMAllInstOneByte.cpp.h', 'one', 1, ),
5967 ( 'IEMAllInst3DNow.cpp.h', '3dnow', 2, ),
5968 ( 'IEMAllInstTwoByte0f.cpp.h', 'two0f', 2, ),
5969 ( 'IEMAllInstThree0f38.cpp.h', 'three0f38', 3, ),
5970 ( 'IEMAllInstThree0f3a.cpp.h', 'three0f3a', 3, ),
5971 ( 'IEMAllInstVexMap1.cpp.h', 'vexmap1', 4, ),
5972 ( 'IEMAllInstVexMap2.cpp.h', 'vexmap2', 4, ),
5973 ( 'IEMAllInstVexMap3.cpp.h', 'vexmap3', 4, ),
5974);
5975
5976def __parseFilesWorker(asFilesAndDefaultMap, sHostArch):
5977 """
5978 Parses all the IEMAllInstruction*.cpp.h files.
5979
5980 Returns a list of the parsers on success.
5981 Raises exception on failure.
5982 """
5983 sSrcDir = os.path.dirname(os.path.abspath(__file__));
5984 cErrors = 0;
5985 aoParsers = [];
5986 for sFilename, sDefaultMap in asFilesAndDefaultMap:
5987 if not os.path.split(sFilename)[0] and not os.path.exists(sFilename):
5988 sFilename = os.path.join(sSrcDir, sFilename);
5989 cThisErrors, oParser = __parseFileByName(sFilename, sDefaultMap, sHostArch);
5990 cErrors += cThisErrors;
5991 aoParsers.append(oParser);
5992 cErrors += __doTestCopying();
5993 cErrors += __applyOnlyTest();
5994
5995 # Total stub stats:
5996 cTotalStubs = 0;
5997 for oInstr in g_aoAllInstructions:
5998 cTotalStubs += oInstr.fStub;
5999 print('debug: %3s%% / %3s stubs out of %4s instructions and %4s MC blocks in total'
6000 % (cTotalStubs * 100 // len(g_aoAllInstructions), cTotalStubs, len(g_aoAllInstructions), len(g_aoMcBlocks),),
6001 file = sys.stderr);
6002
6003 if cErrors != 0:
6004 raise Exception('%d parse errors' % (cErrors,));
6005 return aoParsers;
6006
6007
6008def parseFiles(asFiles, sHostArch = None):
6009 """
6010 Parses a selection of IEMAllInstruction*.cpp.h files.
6011
6012 Returns a list of the parsers on success.
6013 Raises exception on failure.
6014 """
6015 # Look up default maps for the files and call __parseFilesWorker to do the job.
6016 asFilesAndDefaultMap = [];
6017 for sFilename in asFiles:
6018 sName = os.path.split(sFilename)[1].lower();
6019 sMap = None;
6020 for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet:
6021 if aoInfo[0].lower() == sName:
6022 sMap = aoInfo[1];
6023 break;
6024 if not sMap:
6025 raise Exception('Unable to classify file: %s' % (sFilename,));
6026 asFilesAndDefaultMap.append((sFilename, sMap));
6027
6028 return __parseFilesWorker(asFilesAndDefaultMap, sHostArch);
6029
6030
6031def parseAll(sHostArch = None):
6032 """
6033 Parses all the IEMAllInstruction*.cpp.h files.
6034
6035 Returns a list of the parsers on success.
6036 Raises exception on failure.
6037 """
6038 return __parseFilesWorker([aoInfo[0:2] for aoInfo in g_aaoAllInstrFilesAndDefaultMapAndSet], sHostArch);
6039
6040
6041#
6042# Generators (may perhaps move later).
6043#
6044def __formatDisassemblerTableEntry(oInstr):
6045 """
6046 """
6047 sMacro = 'OP';
6048 cMaxOperands = 3;
6049 if len(oInstr.aoOperands) > 3:
6050 sMacro = 'OPVEX'
6051 cMaxOperands = 4;
6052 assert len(oInstr.aoOperands) <= cMaxOperands;
6053
6054 #
6055 # Format string.
6056 #
6057 sTmp = '%s("%s' % (sMacro, oInstr.sMnemonic,);
6058 for iOperand, oOperand in enumerate(oInstr.aoOperands):
6059 sTmp += ' ' if iOperand == 0 else ',';
6060 if g_kdOpTypes[oOperand.sType][2][0] != '%': ## @todo remove upper() later.
6061 sTmp += g_kdOpTypes[oOperand.sType][2].upper(); ## @todo remove upper() later.
6062 else:
6063 sTmp += g_kdOpTypes[oOperand.sType][2];
6064 sTmp += '",';
6065 asColumns = [ sTmp, ];
6066
6067 #
6068 # Decoders.
6069 #
6070 iStart = len(asColumns);
6071 if oInstr.sEncoding is None:
6072 pass;
6073 elif oInstr.sEncoding == 'ModR/M':
6074 # ASSUME the first operand is using the ModR/M encoding
6075 assert len(oInstr.aoOperands) >= 1 and oInstr.aoOperands[0].usesModRM(), "oInstr=%s" % (oInstr,);
6076 asColumns.append('IDX_ParseModRM,');
6077 elif oInstr.sEncoding in [ 'prefix', ]:
6078 for oOperand in oInstr.aoOperands:
6079 asColumns.append('0,');
6080 elif oInstr.sEncoding in [ 'fixed', 'VEX.fixed' ]:
6081 pass;
6082 elif oInstr.sEncoding == 'VEX.ModR/M':
6083 asColumns.append('IDX_ParseModRM,');
6084 elif oInstr.sEncoding == 'vex2':
6085 asColumns.append('IDX_ParseVex2b,')
6086 elif oInstr.sEncoding == 'vex3':
6087 asColumns.append('IDX_ParseVex3b,')
6088 elif oInstr.sEncoding in g_dInstructionMaps:
6089 asColumns.append(g_dInstructionMaps[oInstr.sEncoding].sDisParse + ',');
6090 else:
6091 ## @todo
6092 #IDX_ParseTwoByteEsc,
6093 #IDX_ParseGrp1,
6094 #IDX_ParseShiftGrp2,
6095 #IDX_ParseGrp3,
6096 #IDX_ParseGrp4,
6097 #IDX_ParseGrp5,
6098 #IDX_Parse3DNow,
6099 #IDX_ParseGrp6,
6100 #IDX_ParseGrp7,
6101 #IDX_ParseGrp8,
6102 #IDX_ParseGrp9,
6103 #IDX_ParseGrp10,
6104 #IDX_ParseGrp12,
6105 #IDX_ParseGrp13,
6106 #IDX_ParseGrp14,
6107 #IDX_ParseGrp15,
6108 #IDX_ParseGrp16,
6109 #IDX_ParseThreeByteEsc4,
6110 #IDX_ParseThreeByteEsc5,
6111 #IDX_ParseModFence,
6112 #IDX_ParseEscFP,
6113 #IDX_ParseNopPause,
6114 #IDX_ParseInvOpModRM,
6115 assert False, str(oInstr);
6116
6117 # Check for immediates and stuff in the remaining operands.
6118 for oOperand in oInstr.aoOperands[len(asColumns) - iStart:]:
6119 sIdx = g_kdOpTypes[oOperand.sType][0];
6120 #if sIdx != 'IDX_UseModRM':
6121 asColumns.append(sIdx + ',');
6122 asColumns.extend(['0,'] * (cMaxOperands - (len(asColumns) - iStart)));
6123
6124 #
6125 # Opcode and operands.
6126 #
6127 assert oInstr.sDisEnum, str(oInstr);
6128 asColumns.append(oInstr.sDisEnum + ',');
6129 iStart = len(asColumns)
6130 for oOperand in oInstr.aoOperands:
6131 asColumns.append('OP_PARM_' + g_kdOpTypes[oOperand.sType][3] + ',');
6132 asColumns.extend(['OP_PARM_NONE,'] * (cMaxOperands - (len(asColumns) - iStart)));
6133
6134 #
6135 # Flags.
6136 #
6137 sTmp = '';
6138 for sHint in sorted(oInstr.dHints.keys()):
6139 sDefine = g_kdHints[sHint];
6140 if sDefine.startswith('DISOPTYPE_'):
6141 if sTmp:
6142 sTmp += ' | ' + sDefine;
6143 else:
6144 sTmp += sDefine;
6145 if sTmp:
6146 sTmp += '),';
6147 else:
6148 sTmp += '0),';
6149 asColumns.append(sTmp);
6150
6151 #
6152 # Format the columns into a line.
6153 #
6154 aoffColumns = [4, 29, 49, 65, 77, 89, 109, 125, 141, 157, 183, 199];
6155 sLine = '';
6156 for i, s in enumerate(asColumns):
6157 if len(sLine) < aoffColumns[i]:
6158 sLine += ' ' * (aoffColumns[i] - len(sLine));
6159 else:
6160 sLine += ' ';
6161 sLine += s;
6162
6163 # OP("psrlw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE,
6164 # DISOPTYPE_HARMLESS),
6165 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
6166 # { pszOpcode, idxParse1, idxParse2, idxParse3, 0, opcode, param1, param2, param3, 0, 0, optype }
6167 return sLine;
6168
6169def __checkIfShortTable(aoTableOrdered, oMap):
6170 """
6171 Returns (iInstr, cInstructions, fShortTable)
6172 """
6173
6174 # Determin how much we can trim off.
6175 cInstructions = len(aoTableOrdered);
6176 while cInstructions > 0 and aoTableOrdered[cInstructions - 1] is None:
6177 cInstructions -= 1;
6178
6179 iInstr = 0;
6180 while iInstr < cInstructions and aoTableOrdered[iInstr] is None:
6181 iInstr += 1;
6182
6183 # If we can save more than 30%, we go for the short table version.
6184 if iInstr + len(aoTableOrdered) - cInstructions >= len(aoTableOrdered) // 30:
6185 return (iInstr, cInstructions, True);
6186 _ = oMap; # Use this for overriding.
6187
6188 # Output the full table.
6189 return (0, len(aoTableOrdered), False);
6190
6191def generateDisassemblerTables(oDstFile = sys.stdout):
6192 """
6193 Generates disassembler tables.
6194
6195 Returns exit code.
6196 """
6197
6198 #
6199 # Parse all.
6200 #
6201 try:
6202 parseAll();
6203 except Exception as oXcpt:
6204 print('error: parseAll failed: %s' % (oXcpt,), file = sys.stderr);
6205 traceback.print_exc(file = sys.stderr);
6206 return 1;
6207
6208
6209 #
6210 # The disassembler uses a slightly different table layout to save space,
6211 # since several of the prefix varia
6212 #
6213 aoDisasmMaps = [];
6214 for sName, oMap in sorted(iter(g_dInstructionMaps.items()),
6215 key = lambda aKV: aKV[1].sEncoding + ''.join(aKV[1].asLeadOpcodes)):
6216 if oMap.sSelector != 'byte+pfx':
6217 aoDisasmMaps.append(oMap);
6218 else:
6219 # Split the map by prefix.
6220 aoDisasmMaps.append(oMap.copy(oMap.sName, 'none'));
6221 aoDisasmMaps.append(oMap.copy(oMap.sName + '_66', '0x66'));
6222 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F3', '0xf3'));
6223 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F2', '0xf2'));
6224
6225 #
6226 # Dump each map.
6227 #
6228 asHeaderLines = [];
6229 print("debug: maps=%s\n" % (', '.join([oMap.sName for oMap in aoDisasmMaps]),), file = sys.stderr);
6230 for oMap in aoDisasmMaps:
6231 sName = oMap.sName;
6232
6233 if not sName.startswith("vex"): continue; # only looking at the vex maps at the moment.
6234
6235 #
6236 # Get the instructions for the map and see if we can do a short version or not.
6237 #
6238 aoTableOrder = oMap.getInstructionsInTableOrder();
6239 cEntriesPerByte = oMap.getEntriesPerByte();
6240 (iInstrStart, iInstrEnd, fShortTable) = __checkIfShortTable(aoTableOrder, oMap);
6241
6242 #
6243 # Output the table start.
6244 # Note! Short tables are static and only accessible via the map range record.
6245 #
6246 asLines = [];
6247 asLines.append('/* Generated from: %-11s Selector: %-7s Encoding: %-7s Lead bytes opcodes: %s */'
6248 % ( oMap.sName, oMap.sSelector, oMap.sEncoding, ' '.join(oMap.asLeadOpcodes), ));
6249 if fShortTable:
6250 asLines.append('%sconst DISOPCODE %s[] =' % ('static ' if fShortTable else '', oMap.getDisasTableName(),));
6251 else:
6252 asHeaderLines.append('extern const DISOPCODE %s[%d];' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6253 asLines.append( 'const DISOPCODE %s[%d] =' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6254 asLines.append('{');
6255
6256 if fShortTable and (iInstrStart & ((0x10 * cEntriesPerByte) - 1)) != 0:
6257 asLines.append(' /* %#04x: */' % (iInstrStart,));
6258
6259 #
6260 # Output the instructions.
6261 #
6262 iInstr = iInstrStart;
6263 while iInstr < iInstrEnd:
6264 oInstr = aoTableOrder[iInstr];
6265 if (iInstr & ((0x10 * cEntriesPerByte) - 1)) == 0:
6266 if iInstr != iInstrStart:
6267 asLines.append('');
6268 asLines.append(' /* %x */' % ((iInstr // cEntriesPerByte) >> 4,));
6269
6270 if oInstr is None:
6271 # Invalid. Optimize blocks of invalid instructions.
6272 cInvalidInstrs = 1;
6273 while iInstr + cInvalidInstrs < len(aoTableOrder) and aoTableOrder[iInstr + cInvalidInstrs] is None:
6274 cInvalidInstrs += 1;
6275 if (iInstr & (0x10 * cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= 0x10 * cEntriesPerByte:
6276 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (0x10 * cEntriesPerByte,));
6277 iInstr += 0x10 * cEntriesPerByte - 1;
6278 elif cEntriesPerByte > 1:
6279 if (iInstr & (cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= cEntriesPerByte:
6280 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (cEntriesPerByte,));
6281 iInstr += 3;
6282 else:
6283 asLines.append(' /* %#04x/%d */ INVALID_OPCODE,'
6284 % (iInstr // cEntriesPerByte, iInstr % cEntriesPerByte));
6285 else:
6286 asLines.append(' /* %#04x */ INVALID_OPCODE,' % (iInstr));
6287 elif isinstance(oInstr, list):
6288 if len(oInstr) != 0:
6289 asLines.append(' /* %#04x */ ComplicatedListStuffNeedingWrapper, /* \n -- %s */'
6290 % (iInstr, '\n -- '.join([str(oItem) for oItem in oInstr]),));
6291 else:
6292 asLines.append(__formatDisassemblerTableEntry(oInstr));
6293 else:
6294 asLines.append(__formatDisassemblerTableEntry(oInstr));
6295
6296 iInstr += 1;
6297
6298 if iInstrStart >= iInstrEnd:
6299 asLines.append(' /* dummy */ INVALID_OPCODE');
6300
6301 asLines.append('};');
6302 asLines.append('AssertCompile(RT_ELEMENTS(%s) == %s);' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
6303
6304 #
6305 # We always emit a map range record, assuming the linker will eliminate the unnecessary ones.
6306 #
6307 asHeaderLines.append('extern const DISOPMAPDESC %sRange;' % (oMap.getDisasRangeName()));
6308 asLines.append('const DISOPMAPDESC %s = { &%s[0], %#04x, RT_ELEMENTS(%s) };'
6309 % (oMap.getDisasRangeName(), oMap.getDisasTableName(), iInstrStart, oMap.getDisasTableName(),));
6310
6311 #
6312 # Write out the lines.
6313 #
6314 oDstFile.write('\n'.join(asLines));
6315 oDstFile.write('\n');
6316 oDstFile.write('\n');
6317 #break; #for now
6318 return 0;
6319
6320if __name__ == '__main__':
6321 sys.exit(generateDisassemblerTables());
6322
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