VirtualBox

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

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

VMM/IEM: IEM_MC_LOCAL_EFLAGS. bugref:10376

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

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