VirtualBox

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

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

VMM/IEM: Native IEM_MC_IF_EFL_BIT_NOT_SET translation. bugref:10371

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

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