VirtualBox

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

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

VMM/IEM: Implement native emitters for IEM_MC_LOCAL_ASSIGN(), IEM_MC_AND_ARG_U16()/IEM_MC_AND_ARG_U32()/IEM_MC_AND_ARG_U64(), IEM_MC_SHL_LOCAL_S16()/IEM_MC_SHL_LOCAL_S32()/IEM_MC_SHL_LOCAL_S64(), IEM_MC_SAR_LOCAL_S16()/IEM_MC_SAR_LOCAL_S32()/IEM_MC_SAR_LOCAL_S64() and IEM_MC_ADD_LOCAL_S16_TO_EFF_ADDR()/IEM_MC_ADD_LOCAL_S32_TO_EFF_ADDR()/IEM_MC_ADD_LOCAL_S64_TO_EFF_ADDR() (enables recompilation of bt/btr/bts instructions), bugref:10371

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

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