VirtualBox

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

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

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