VirtualBox

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

Last change on this file since 104129 was 104129, checked in by vboxsync, 13 months ago

VMM/IEM: Rework MXCSR handling for SSE instructions, bugref:10641

The old approach by referencing the X86FXSTATE and accessing the MXCSR value there
prevents us from keeping the MXCSR shadowed in a host register for SIMD guest code
causing unecessary memory accesses. It also prevents avoiding skipping dirty guest registers
because the instruction helpers would have access the to CPUMCTX structure.

The new approach passes the guest MXCSR as the first argument of the helper callback and
the helper returns the MXCSR with the new exception flags being set as a return value.
With this the helpers only work on arguments supplied and don't access anything in CPUMCTX
directly which allows the recompiler to avoid flushing pending register writes unless they get
used.

As a bonus this also gets rid of the IEMSSERESULT struct which was required because the helpers
are restricted to 4 arguments due to restrictions on x86 for the assembly helpers in IEMAllAImpl.asm

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

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