VirtualBox

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

Last change on this file since 104087 was 104087, checked in by vboxsync, 8 months ago

VMM/IEM: Implement native emitters for IEM_MC_STORE_XREG_U8() and IEM_MC_STORE_XREG_U16(), bugref:10614

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

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