VirtualBox

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

Last change on this file since 106179 was 106179, checked in by vboxsync, 5 months ago

VMM/IEM: Reworked the div, idiv, mul and imul assembly workers and how we raise division error exceptions. The latter is to simplify eflags management. bugref:10720

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