VirtualBox

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

最後變更 在這個檔案從103376是 103256,由 vboxsync 提交於 14 月 前

VMM/IEM: Fix regression causing alignment exceptions for SSE/AVX based unaligned data fetches and stores which are handled fine on real hardware, bugref:9898

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

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