VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/IEMAllInstructionsPython.py@ 98842

Last change on this file since 98842 was 98842, checked in by vboxsync, 22 months ago

VMM/IEM,ValKit: Require explicit instruction file loading call for IEMAllInstructionsPython.py. bugref:10369

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 169.7 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# $Id: IEMAllInstructionsPython.py 98842 2023-03-06 17:14:45Z 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: 98842 $"
47
48# pylint: disable=anomalous-backslash-in-string
49
50# Standard python imports.
51import os
52import re
53import sys
54
55## Only the main script needs to modify the path.
56#g_ksValidationKitDir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
57# 'ValidationKit');
58#sys.path.append(g_ksValidationKitDir);
59#
60#from common import utils; - Windows build boxes doesn't have pywin32.
61
62# Python 3 hacks:
63if sys.version_info[0] >= 3:
64 long = int; # pylint: disable=redefined-builtin,invalid-name
65
66
67g_kdX86EFlagsConstants = {
68 'X86_EFL_CF': 0x00000001, # RT_BIT_32(0)
69 'X86_EFL_1': 0x00000002, # RT_BIT_32(1)
70 'X86_EFL_PF': 0x00000004, # RT_BIT_32(2)
71 'X86_EFL_AF': 0x00000010, # RT_BIT_32(4)
72 'X86_EFL_ZF': 0x00000040, # RT_BIT_32(6)
73 'X86_EFL_SF': 0x00000080, # RT_BIT_32(7)
74 'X86_EFL_TF': 0x00000100, # RT_BIT_32(8)
75 'X86_EFL_IF': 0x00000200, # RT_BIT_32(9)
76 'X86_EFL_DF': 0x00000400, # RT_BIT_32(10)
77 'X86_EFL_OF': 0x00000800, # RT_BIT_32(11)
78 'X86_EFL_IOPL': 0x00003000, # (RT_BIT_32(12) | RT_BIT_32(13))
79 'X86_EFL_NT': 0x00004000, # RT_BIT_32(14)
80 'X86_EFL_RF': 0x00010000, # RT_BIT_32(16)
81 'X86_EFL_VM': 0x00020000, # RT_BIT_32(17)
82 'X86_EFL_AC': 0x00040000, # RT_BIT_32(18)
83 'X86_EFL_VIF': 0x00080000, # RT_BIT_32(19)
84 'X86_EFL_VIP': 0x00100000, # RT_BIT_32(20)
85 'X86_EFL_ID': 0x00200000, # RT_BIT_32(21)
86 'X86_EFL_LIVE_MASK': 0x003f7fd5, # UINT32_C(0x003f7fd5)
87 'X86_EFL_RA1_MASK': 0x00000002, # RT_BIT_32(1)
88};
89
90## EFlags values allowed in \@opfltest, \@opflmodify, \@opflundef, \@opflset, and \@opflclear.
91g_kdEFlagsMnemonics = {
92 # Debugger flag notation (sorted by value):
93 'cf': 'X86_EFL_CF', ##< Carry Flag.
94 'nc': '!X86_EFL_CF', ##< No Carry.
95
96 'po': 'X86_EFL_PF', ##< Parity Pdd.
97 'pe': '!X86_EFL_PF', ##< Parity Even.
98
99 'af': 'X86_EFL_AF', ##< Aux Flag.
100 'na': '!X86_EFL_AF', ##< No Aux.
101
102 'zr': 'X86_EFL_ZF', ##< ZeRo.
103 'nz': '!X86_EFL_ZF', ##< No Zero.
104
105 'ng': 'X86_EFL_SF', ##< NeGative (sign).
106 'pl': '!X86_EFL_SF', ##< PLuss (sign).
107
108 'tf': 'X86_EFL_TF', ##< Trap flag.
109
110 'ei': 'X86_EFL_IF', ##< Enabled Interrupts.
111 'di': '!X86_EFL_IF', ##< Disabled Interrupts.
112
113 'dn': 'X86_EFL_DF', ##< DowN (string op direction).
114 'up': '!X86_EFL_DF', ##< UP (string op direction).
115
116 'ov': 'X86_EFL_OF', ##< OVerflow.
117 'nv': '!X86_EFL_OF', ##< No Overflow.
118
119 'nt': 'X86_EFL_NT', ##< Nested Task.
120 'rf': 'X86_EFL_RF', ##< Resume Flag.
121 'vm': 'X86_EFL_VM', ##< Virtual-8086 Mode.
122 'ac': 'X86_EFL_AC', ##< Alignment Check.
123 'vif': 'X86_EFL_VIF', ##< Virtual Interrupt Flag.
124 'vip': 'X86_EFL_VIP', ##< Virtual Interrupt Pending.
125
126 # Reference manual notation not covered above (sorted by value):
127 'pf': 'X86_EFL_PF',
128 'zf': 'X86_EFL_ZF',
129 'sf': 'X86_EFL_SF',
130 'if': 'X86_EFL_IF',
131 'df': 'X86_EFL_DF',
132 'of': 'X86_EFL_OF',
133 'iopl': 'X86_EFL_IOPL',
134 'id': 'X86_EFL_ID',
135};
136
137## Constants and values for CR0.
138g_kdX86Cr0Constants = {
139 'X86_CR0_PE': 0x00000001, # RT_BIT_32(0)
140 'X86_CR0_MP': 0x00000002, # RT_BIT_32(1)
141 'X86_CR0_EM': 0x00000004, # RT_BIT_32(2)
142 'X86_CR0_TS': 0x00000008, # RT_BIT_32(3)
143 'X86_CR0_ET': 0x00000010, # RT_BIT_32(4)
144 'X86_CR0_NE': 0x00000020, # RT_BIT_32(5)
145 'X86_CR0_WP': 0x00010000, # RT_BIT_32(16)
146 'X86_CR0_AM': 0x00040000, # RT_BIT_32(18)
147 'X86_CR0_NW': 0x20000000, # RT_BIT_32(29)
148 'X86_CR0_CD': 0x40000000, # RT_BIT_32(30)
149 'X86_CR0_PG': 0x80000000, # RT_BIT_32(31)
150};
151
152## Constants and values for CR4.
153g_kdX86Cr4Constants = {
154 'X86_CR4_VME': 0x00000001, # RT_BIT_32(0)
155 'X86_CR4_PVI': 0x00000002, # RT_BIT_32(1)
156 'X86_CR4_TSD': 0x00000004, # RT_BIT_32(2)
157 'X86_CR4_DE': 0x00000008, # RT_BIT_32(3)
158 'X86_CR4_PSE': 0x00000010, # RT_BIT_32(4)
159 'X86_CR4_PAE': 0x00000020, # RT_BIT_32(5)
160 'X86_CR4_MCE': 0x00000040, # RT_BIT_32(6)
161 'X86_CR4_PGE': 0x00000080, # RT_BIT_32(7)
162 'X86_CR4_PCE': 0x00000100, # RT_BIT_32(8)
163 'X86_CR4_OSFXSR': 0x00000200, # RT_BIT_32(9)
164 'X86_CR4_OSXMMEEXCPT': 0x00000400, # RT_BIT_32(10)
165 'X86_CR4_VMXE': 0x00002000, # RT_BIT_32(13)
166 'X86_CR4_SMXE': 0x00004000, # RT_BIT_32(14)
167 'X86_CR4_PCIDE': 0x00020000, # RT_BIT_32(17)
168 'X86_CR4_OSXSAVE': 0x00040000, # RT_BIT_32(18)
169 'X86_CR4_SMEP': 0x00100000, # RT_BIT_32(20)
170 'X86_CR4_SMAP': 0x00200000, # RT_BIT_32(21)
171 'X86_CR4_PKE': 0x00400000, # RT_BIT_32(22)
172};
173
174## XSAVE components (XCR0).
175g_kdX86XSaveCConstants = {
176 'XSAVE_C_X87': 0x00000001,
177 'XSAVE_C_SSE': 0x00000002,
178 'XSAVE_C_YMM': 0x00000004,
179 'XSAVE_C_BNDREGS': 0x00000008,
180 'XSAVE_C_BNDCSR': 0x00000010,
181 'XSAVE_C_OPMASK': 0x00000020,
182 'XSAVE_C_ZMM_HI256': 0x00000040,
183 'XSAVE_C_ZMM_16HI': 0x00000080,
184 'XSAVE_C_PKRU': 0x00000200,
185 'XSAVE_C_LWP': 0x4000000000000000,
186 'XSAVE_C_X': 0x8000000000000000,
187 'XSAVE_C_ALL_AVX': 0x000000c4, # For clearing all AVX bits.
188 'XSAVE_C_ALL_AVX_SSE': 0x000000c6, # For clearing all AVX and SSE bits.
189};
190
191
192## \@op[1-4] locations
193g_kdOpLocations = {
194 'reg': [], ## modrm.reg
195 'rm': [], ## modrm.rm
196 'imm': [], ## immediate instruction data
197 'vvvv': [], ## VEX.vvvv
198
199 # fixed registers.
200 'AL': [],
201 'rAX': [],
202 'rDX': [],
203 'rSI': [],
204 'rDI': [],
205 'rFLAGS': [],
206 'CS': [],
207 'DS': [],
208 'ES': [],
209 'FS': [],
210 'GS': [],
211 'SS': [],
212};
213
214## \@op[1-4] types
215##
216## Value fields:
217## - 0: the normal IDX_ParseXXX handler (IDX_UseModRM == IDX_ParseModRM).
218## - 1: the location (g_kdOpLocations).
219## - 2: disassembler format string version of the type.
220## - 3: disassembler OP_PARAM_XXX (XXX only).
221## - 4: IEM form matching instruction.
222##
223## Note! See the A.2.1 in SDM vol 2 for the type names.
224g_kdOpTypes = {
225 # Fixed addresses
226 'Ap': ( 'IDX_ParseImmAddrF', 'imm', '%Ap', 'Ap', 'FIXED', ),
227
228 # ModR/M.rm
229 'Eb': ( 'IDX_UseModRM', 'rm', '%Eb', 'Eb', 'RM', ),
230 'Ed': ( 'IDX_UseModRM', 'rm', '%Ed', 'Ed', 'RM', ),
231 'Ed_WO': ( 'IDX_UseModRM', 'rm', '%Ed', 'Ed', 'RM', ),
232 'Eq': ( 'IDX_UseModRM', 'rm', '%Eq', 'Eq', 'RM', ),
233 'Eq_WO': ( 'IDX_UseModRM', 'rm', '%Eq', 'Eq', 'RM', ),
234 'Ew': ( 'IDX_UseModRM', 'rm', '%Ew', 'Ew', 'RM', ),
235 'Ev': ( 'IDX_UseModRM', 'rm', '%Ev', 'Ev', 'RM', ),
236 'Ey': ( 'IDX_UseModRM', 'rm', '%Ey', 'Ey', 'RM', ),
237 'Qd': ( 'IDX_UseModRM', 'rm', '%Qd', 'Qd', 'RM', ),
238 'Qq': ( 'IDX_UseModRM', 'rm', '%Qq', 'Qq', 'RM', ),
239 'Qq_WO': ( 'IDX_UseModRM', 'rm', '%Qq', 'Qq', 'RM', ),
240 'Wss': ( 'IDX_UseModRM', 'rm', '%Wss', 'Wss', 'RM', ),
241 'Wss_WO': ( 'IDX_UseModRM', 'rm', '%Wss', 'Wss', 'RM', ),
242 'Wsd': ( 'IDX_UseModRM', 'rm', '%Wsd', 'Wsd', 'RM', ),
243 'Wsd_WO': ( 'IDX_UseModRM', 'rm', '%Wsd', 'Wsd', 'RM', ),
244 'Wps': ( 'IDX_UseModRM', 'rm', '%Wps', 'Wps', 'RM', ),
245 'Wps_WO': ( 'IDX_UseModRM', 'rm', '%Wps', 'Wps', 'RM', ),
246 'Wpd': ( 'IDX_UseModRM', 'rm', '%Wpd', 'Wpd', 'RM', ),
247 'Wpd_WO': ( 'IDX_UseModRM', 'rm', '%Wpd', 'Wpd', 'RM', ),
248 'Wdq': ( 'IDX_UseModRM', 'rm', '%Wdq', 'Wdq', 'RM', ),
249 'Wdq_WO': ( 'IDX_UseModRM', 'rm', '%Wdq', 'Wdq', 'RM', ),
250 'Wq': ( 'IDX_UseModRM', 'rm', '%Wq', 'Wq', 'RM', ),
251 'Wq_WO': ( 'IDX_UseModRM', 'rm', '%Wq', 'Wq', 'RM', ),
252 'WqZxReg_WO': ( 'IDX_UseModRM', 'rm', '%Wq', 'Wq', 'RM', ),
253 'Wx': ( 'IDX_UseModRM', 'rm', '%Wx', 'Wx', 'RM', ),
254 'Wx_WO': ( 'IDX_UseModRM', 'rm', '%Wx', 'Wx', 'RM', ),
255
256 # ModR/M.rm - register only.
257 'Uq': ( 'IDX_UseModRM', 'rm', '%Uq', 'Uq', 'REG' ),
258 'UqHi': ( 'IDX_UseModRM', 'rm', '%Uq', 'UqHi', 'REG' ),
259 'Uss': ( 'IDX_UseModRM', 'rm', '%Uss', 'Uss', 'REG' ),
260 'Uss_WO': ( 'IDX_UseModRM', 'rm', '%Uss', 'Uss', 'REG' ),
261 'Usd': ( 'IDX_UseModRM', 'rm', '%Usd', 'Usd', 'REG' ),
262 'Usd_WO': ( 'IDX_UseModRM', 'rm', '%Usd', 'Usd', 'REG' ),
263 'Ux': ( 'IDX_UseModRM', 'rm', '%Ux', 'Ux', 'REG' ),
264 'Nq': ( 'IDX_UseModRM', 'rm', '%Qq', 'Nq', 'REG' ),
265
266 # ModR/M.rm - memory only.
267 'Ma': ( 'IDX_UseModRM', 'rm', '%Ma', 'Ma', 'MEM', ), ##< Only used by BOUND.
268 'Mb_RO': ( 'IDX_UseModRM', 'rm', '%Mb', 'Mb', 'MEM', ),
269 'Md': ( 'IDX_UseModRM', 'rm', '%Md', 'Md', 'MEM', ),
270 'Md_RO': ( 'IDX_UseModRM', 'rm', '%Md', 'Md', 'MEM', ),
271 'Md_WO': ( 'IDX_UseModRM', 'rm', '%Md', 'Md', 'MEM', ),
272 'Mdq': ( 'IDX_UseModRM', 'rm', '%Mdq', 'Mdq', 'MEM', ),
273 'Mdq_WO': ( 'IDX_UseModRM', 'rm', '%Mdq', 'Mdq', 'MEM', ),
274 'Mq': ( 'IDX_UseModRM', 'rm', '%Mq', 'Mq', 'MEM', ),
275 'Mq_WO': ( 'IDX_UseModRM', 'rm', '%Mq', 'Mq', 'MEM', ),
276 'Mps_WO': ( 'IDX_UseModRM', 'rm', '%Mps', 'Mps', 'MEM', ),
277 'Mpd_WO': ( 'IDX_UseModRM', 'rm', '%Mpd', 'Mpd', 'MEM', ),
278 'Mx': ( 'IDX_UseModRM', 'rm', '%Mx', 'Mx', 'MEM', ),
279 'Mx_WO': ( 'IDX_UseModRM', 'rm', '%Mx', 'Mx', 'MEM', ),
280 'M_RO': ( 'IDX_UseModRM', 'rm', '%M', 'M', 'MEM', ),
281 'M_RW': ( 'IDX_UseModRM', 'rm', '%M', 'M', 'MEM', ),
282
283 # ModR/M.reg
284 'Gb': ( 'IDX_UseModRM', 'reg', '%Gb', 'Gb', '', ),
285 'Gw': ( 'IDX_UseModRM', 'reg', '%Gw', 'Gw', '', ),
286 'Gd': ( 'IDX_UseModRM', 'reg', '%Gd', 'Gd', '', ),
287 'Gv': ( 'IDX_UseModRM', 'reg', '%Gv', 'Gv', '', ),
288 'Gv_RO': ( 'IDX_UseModRM', 'reg', '%Gv', 'Gv', '', ),
289 'Gy': ( 'IDX_UseModRM', 'reg', '%Gy', 'Gy', '', ),
290 'Pd': ( 'IDX_UseModRM', 'reg', '%Pd', 'Pd', '', ),
291 'PdZx_WO': ( 'IDX_UseModRM', 'reg', '%Pd', 'PdZx', '', ),
292 'Pq': ( 'IDX_UseModRM', 'reg', '%Pq', 'Pq', '', ),
293 'Pq_WO': ( 'IDX_UseModRM', 'reg', '%Pq', 'Pq', '', ),
294 'Vd': ( 'IDX_UseModRM', 'reg', '%Vd', 'Vd', '', ),
295 'Vd_WO': ( 'IDX_UseModRM', 'reg', '%Vd', 'Vd', '', ),
296 'VdZx_WO': ( 'IDX_UseModRM', 'reg', '%Vd', 'Vd', '', ),
297 'Vdq': ( 'IDX_UseModRM', 'reg', '%Vdq', 'Vdq', '', ),
298 'Vss': ( 'IDX_UseModRM', 'reg', '%Vss', 'Vss', '', ),
299 'Vss_WO': ( 'IDX_UseModRM', 'reg', '%Vss', 'Vss', '', ),
300 'VssZx_WO': ( 'IDX_UseModRM', 'reg', '%Vss', 'Vss', '', ),
301 'Vsd': ( 'IDX_UseModRM', 'reg', '%Vsd', 'Vsd', '', ),
302 'Vsd_WO': ( 'IDX_UseModRM', 'reg', '%Vsd', 'Vsd', '', ),
303 'VsdZx_WO': ( 'IDX_UseModRM', 'reg', '%Vsd', 'Vsd', '', ),
304 'Vps': ( 'IDX_UseModRM', 'reg', '%Vps', 'Vps', '', ),
305 'Vps_WO': ( 'IDX_UseModRM', 'reg', '%Vps', 'Vps', '', ),
306 'Vpd': ( 'IDX_UseModRM', 'reg', '%Vpd', 'Vpd', '', ),
307 'Vpd_WO': ( 'IDX_UseModRM', 'reg', '%Vpd', 'Vpd', '', ),
308 'Vq': ( 'IDX_UseModRM', 'reg', '%Vq', 'Vq', '', ),
309 'Vq_WO': ( 'IDX_UseModRM', 'reg', '%Vq', 'Vq', '', ),
310 'Vdq_WO': ( 'IDX_UseModRM', 'reg', '%Vdq', 'Vdq', '', ),
311 'VqHi': ( 'IDX_UseModRM', 'reg', '%Vdq', 'VdqHi', '', ),
312 'VqHi_WO': ( 'IDX_UseModRM', 'reg', '%Vdq', 'VdqHi', '', ),
313 'VqZx_WO': ( 'IDX_UseModRM', 'reg', '%Vq', 'VqZx', '', ),
314 'Vx': ( 'IDX_UseModRM', 'reg', '%Vx', 'Vx', '', ),
315 'Vx_WO': ( 'IDX_UseModRM', 'reg', '%Vx', 'Vx', '', ),
316
317 # VEX.vvvv
318 'By': ( 'IDX_UseModRM', 'vvvv', '%By', 'By', 'V', ),
319 'Hps': ( 'IDX_UseModRM', 'vvvv', '%Hps', 'Hps', 'V', ),
320 'Hpd': ( 'IDX_UseModRM', 'vvvv', '%Hpd', 'Hpd', 'V', ),
321 'HssHi': ( 'IDX_UseModRM', 'vvvv', '%Hx', 'HssHi', 'V', ),
322 'HsdHi': ( 'IDX_UseModRM', 'vvvv', '%Hx', 'HsdHi', 'V', ),
323 'Hq': ( 'IDX_UseModRM', 'vvvv', '%Hq', 'Hq', 'V', ),
324 'HqHi': ( 'IDX_UseModRM', 'vvvv', '%Hq', 'HqHi', 'V', ),
325 'Hx': ( 'IDX_UseModRM', 'vvvv', '%Hx', 'Hx', 'V', ),
326
327 # Immediate values.
328 'Ib': ( 'IDX_ParseImmByte', 'imm', '%Ib', 'Ib', '', ), ##< NB! Could be IDX_ParseImmByteSX for some instrs.
329 'Iw': ( 'IDX_ParseImmUshort', 'imm', '%Iw', 'Iw', '', ),
330 'Id': ( 'IDX_ParseImmUlong', 'imm', '%Id', 'Id', '', ),
331 'Iq': ( 'IDX_ParseImmQword', 'imm', '%Iq', 'Iq', '', ),
332 'Iv': ( 'IDX_ParseImmV', 'imm', '%Iv', 'Iv', '', ), ##< o16: word, o32: dword, o64: qword
333 'Iz': ( 'IDX_ParseImmZ', 'imm', '%Iz', 'Iz', '', ), ##< o16: word, o32|o64:dword
334
335 # Address operands (no ModR/M).
336 'Ob': ( 'IDX_ParseImmAddr', 'imm', '%Ob', 'Ob', '', ),
337 'Ov': ( 'IDX_ParseImmAddr', 'imm', '%Ov', 'Ov', '', ),
338
339 # Relative jump targets
340 'Jb': ( 'IDX_ParseImmBRel', 'imm', '%Jb', 'Jb', '', ),
341 'Jv': ( 'IDX_ParseImmVRel', 'imm', '%Jv', 'Jv', '', ),
342
343 # DS:rSI
344 'Xb': ( 'IDX_ParseXb', 'rSI', '%eSI', 'Xb', '', ),
345 'Xv': ( 'IDX_ParseXv', 'rSI', '%eSI', 'Xv', '', ),
346 # ES:rDI
347 'Yb': ( 'IDX_ParseYb', 'rDI', '%eDI', 'Yb', '', ),
348 'Yv': ( 'IDX_ParseYv', 'rDI', '%eDI', 'Yv', '', ),
349
350 'Fv': ( 'IDX_ParseFixedReg', 'rFLAGS', '%Fv', 'Fv', '', ),
351
352 # Fixed registers.
353 'AL': ( 'IDX_ParseFixedReg', 'AL', 'al', 'REG_AL', '', ),
354 'rAX': ( 'IDX_ParseFixedReg', 'rAX', '%eAX', 'REG_EAX', '', ),
355 'rDX': ( 'IDX_ParseFixedReg', 'rDX', '%eDX', 'REG_EDX', '', ),
356 'CS': ( 'IDX_ParseFixedReg', 'CS', 'cs', 'REG_CS', '', ), # 8086: push CS
357 'DS': ( 'IDX_ParseFixedReg', 'DS', 'ds', 'REG_DS', '', ),
358 'ES': ( 'IDX_ParseFixedReg', 'ES', 'es', 'REG_ES', '', ),
359 'FS': ( 'IDX_ParseFixedReg', 'FS', 'fs', 'REG_FS', '', ),
360 'GS': ( 'IDX_ParseFixedReg', 'GS', 'gs', 'REG_GS', '', ),
361 'SS': ( 'IDX_ParseFixedReg', 'SS', 'ss', 'REG_SS', '', ),
362};
363
364# IDX_ParseFixedReg
365# IDX_ParseVexDest
366
367
368## IEMFORM_XXX mappings.
369g_kdIemForms = { # sEncoding, [ sWhere1, ... ] opcodesub ),
370 'RM': ( 'ModR/M', [ 'reg', 'rm' ], '', ),
371 'RM_REG': ( 'ModR/M', [ 'reg', 'rm' ], '11 mr/reg', ),
372 'RM_MEM': ( 'ModR/M', [ 'reg', 'rm' ], '!11 mr/reg', ),
373 'RMI': ( 'ModR/M', [ 'reg', 'rm', 'imm' ], '', ),
374 'RMI_REG': ( 'ModR/M', [ 'reg', 'rm', 'imm' ], '11 mr/reg', ),
375 'RMI_MEM': ( 'ModR/M', [ 'reg', 'rm', 'imm' ], '!11 mr/reg', ),
376 'MR': ( 'ModR/M', [ 'rm', 'reg' ], '', ),
377 'MR_REG': ( 'ModR/M', [ 'rm', 'reg' ], '11 mr/reg', ),
378 'MR_MEM': ( 'ModR/M', [ 'rm', 'reg' ], '!11 mr/reg', ),
379 'MRI': ( 'ModR/M', [ 'rm', 'reg', 'imm' ], '', ),
380 'MRI_REG': ( 'ModR/M', [ 'rm', 'reg', 'imm' ], '11 mr/reg', ),
381 'MRI_MEM': ( 'ModR/M', [ 'rm', 'reg', 'imm' ], '!11 mr/reg', ),
382 'M': ( 'ModR/M', [ 'rm', ], '', ),
383 'M_REG': ( 'ModR/M', [ 'rm', ], '', ),
384 'M_MEM': ( 'ModR/M', [ 'rm', ], '', ),
385 'R': ( 'ModR/M', [ 'reg', ], '', ),
386
387 'VEX_RM': ( 'VEX.ModR/M', [ 'reg', 'rm' ], '', ),
388 'VEX_RM_REG': ( 'VEX.ModR/M', [ 'reg', 'rm' ], '11 mr/reg', ),
389 'VEX_RM_MEM': ( 'VEX.ModR/M', [ 'reg', 'rm' ], '!11 mr/reg', ),
390 'VEX_MR': ( 'VEX.ModR/M', [ 'rm', 'reg' ], '', ),
391 'VEX_MR_REG': ( 'VEX.ModR/M', [ 'rm', 'reg' ], '11 mr/reg', ),
392 'VEX_MR_MEM': ( 'VEX.ModR/M', [ 'rm', 'reg' ], '!11 mr/reg', ),
393 'VEX_M': ( 'VEX.ModR/M', [ 'rm', ], '' ),
394 'VEX_M_REG': ( 'VEX.ModR/M', [ 'rm', ], '' ),
395 'VEX_M_MEM': ( 'VEX.ModR/M', [ 'rm', ], '' ),
396 'VEX_R': ( 'VEX.ModR/M', [ 'reg', ], '' ),
397 'VEX_RVM': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm' ], '', ),
398 'VEX_RVM_REG': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm' ], '11 mr/reg', ),
399 'VEX_RVM_MEM': ( 'VEX.ModR/M', [ 'reg', 'vvvv', 'rm' ], '!11 mr/reg', ),
400 'VEX_RMV': ( 'VEX.ModR/M', [ 'reg', 'rm', 'vvvv' ], '', ),
401 'VEX_RMV_REG': ( 'VEX.ModR/M', [ 'reg', 'rm', 'vvvv' ], '11 mr/reg', ),
402 'VEX_RMV_MEM': ( 'VEX.ModR/M', [ 'reg', 'rm', 'vvvv' ], '!11 mr/reg', ),
403 'VEX_RMI': ( 'VEX.ModR/M', [ 'reg', 'rm', 'imm' ], '', ),
404 'VEX_RMI_REG': ( 'VEX.ModR/M', [ 'reg', 'rm', 'imm' ], '11 mr/reg', ),
405 'VEX_RMI_MEM': ( 'VEX.ModR/M', [ 'reg', 'rm', 'imm' ], '!11 mr/reg', ),
406 'VEX_MVR': ( 'VEX.ModR/M', [ 'rm', 'vvvv', 'reg' ], '', ),
407 'VEX_MVR_REG': ( 'VEX.ModR/M', [ 'rm', 'vvvv', 'reg' ], '11 mr/reg', ),
408 'VEX_MVR_MEM': ( 'VEX.ModR/M', [ 'rm', 'vvvv', 'reg' ], '!11 mr/reg', ),
409
410 'VEX_VM': ( 'VEX.ModR/M', [ 'vvvv', 'rm' ], '', ),
411 'VEX_VM_REG': ( 'VEX.ModR/M', [ 'vvvv', 'rm' ], '11 mr/reg', ),
412 'VEX_VM_MEM': ( 'VEX.ModR/M', [ 'vvvv', 'rm' ], '!11 mr/reg', ),
413
414 'FIXED': ( 'fixed', None, '', ),
415};
416
417## \@oppfx values.
418g_kdPrefixes = {
419 'none': [],
420 '0x66': [],
421 '0xf3': [],
422 '0xf2': [],
423};
424
425## Special \@opcode tag values.
426g_kdSpecialOpcodes = {
427 '/reg': [],
428 'mr/reg': [],
429 '11 /reg': [],
430 '!11 /reg': [],
431 '11 mr/reg': [],
432 '!11 mr/reg': [],
433};
434
435## Special \@opcodesub tag values.
436## The first value is the real value for aliases.
437## The second value is for bs3cg1.
438g_kdSubOpcodes = {
439 'none': [ None, '', ],
440 '11 mr/reg': [ '11 mr/reg', '', ],
441 '11': [ '11 mr/reg', '', ], ##< alias
442 '!11 mr/reg': [ '!11 mr/reg', '', ],
443 '!11': [ '!11 mr/reg', '', ], ##< alias
444 'rex.w=0': [ 'rex.w=0', 'WZ', ],
445 'w=0': [ 'rex.w=0', '', ], ##< alias
446 'rex.w=1': [ 'rex.w=1', 'WNZ', ],
447 'w=1': [ 'rex.w=1', '', ], ##< alias
448 'vex.l=0': [ 'vex.l=0', 'L0', ],
449 'vex.l=1': [ 'vex.l=0', 'L1', ],
450 '11 mr/reg vex.l=0': [ '11 mr/reg vex.l=0', 'L0', ],
451 '11 mr/reg vex.l=1': [ '11 mr/reg vex.l=1', 'L1', ],
452 '!11 mr/reg vex.l=0': [ '!11 mr/reg vex.l=0', 'L0', ],
453 '!11 mr/reg vex.l=1': [ '!11 mr/reg vex.l=1', 'L1', ],
454};
455
456## Valid values for \@openc
457g_kdEncodings = {
458 'ModR/M': [ 'BS3CG1ENC_MODRM', ], ##< ModR/M
459 'VEX.ModR/M': [ 'BS3CG1ENC_VEX_MODRM', ], ##< VEX...ModR/M
460 'fixed': [ 'BS3CG1ENC_FIXED', ], ##< Fixed encoding (address, registers, unused, etc).
461 'VEX.fixed': [ 'BS3CG1ENC_VEX_FIXED', ], ##< VEX + fixed encoding (address, registers, unused, etc).
462 'prefix': [ None, ], ##< Prefix
463};
464
465## \@opunused, \@opinvalid, \@opinvlstyle
466g_kdInvalidStyles = {
467 'immediate': [], ##< CPU stops decoding immediately after the opcode.
468 'vex.modrm': [], ##< VEX+ModR/M, everyone.
469 'intel-modrm': [], ##< Intel decodes ModR/M.
470 'intel-modrm-imm8': [], ##< Intel decodes ModR/M and an 8-byte immediate.
471 'intel-opcode-modrm': [], ##< Intel decodes another opcode byte followed by ModR/M. (Unused extension tables.)
472 'intel-opcode-modrm-imm8': [], ##< Intel decodes another opcode byte followed by ModR/M and an 8-byte immediate.
473};
474
475g_kdCpuNames = {
476 '8086': (),
477 '80186': (),
478 '80286': (),
479 '80386': (),
480 '80486': (),
481};
482
483## \@opcpuid
484g_kdCpuIdFlags = {
485 'vme': 'X86_CPUID_FEATURE_EDX_VME',
486 'tsc': 'X86_CPUID_FEATURE_EDX_TSC',
487 'msr': 'X86_CPUID_FEATURE_EDX_MSR',
488 'cx8': 'X86_CPUID_FEATURE_EDX_CX8',
489 'sep': 'X86_CPUID_FEATURE_EDX_SEP',
490 'cmov': 'X86_CPUID_FEATURE_EDX_CMOV',
491 'clfsh': 'X86_CPUID_FEATURE_EDX_CLFSH',
492 'clflushopt': 'X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT',
493 'mmx': 'X86_CPUID_FEATURE_EDX_MMX',
494 'fxsr': 'X86_CPUID_FEATURE_EDX_FXSR',
495 'sse': 'X86_CPUID_FEATURE_EDX_SSE',
496 'sse2': 'X86_CPUID_FEATURE_EDX_SSE2',
497 'sse3': 'X86_CPUID_FEATURE_ECX_SSE3',
498 'pclmul': 'X86_CPUID_FEATURE_ECX_DTES64',
499 'monitor': 'X86_CPUID_FEATURE_ECX_CPLDS',
500 'vmx': 'X86_CPUID_FEATURE_ECX_VMX',
501 'smx': 'X86_CPUID_FEATURE_ECX_TM2',
502 'ssse3': 'X86_CPUID_FEATURE_ECX_SSSE3',
503 'fma': 'X86_CPUID_FEATURE_ECX_FMA',
504 'cx16': 'X86_CPUID_FEATURE_ECX_CX16',
505 'pcid': 'X86_CPUID_FEATURE_ECX_PCID',
506 'sse4.1': 'X86_CPUID_FEATURE_ECX_SSE4_1',
507 'sse4.2': 'X86_CPUID_FEATURE_ECX_SSE4_2',
508 'movbe': 'X86_CPUID_FEATURE_ECX_MOVBE',
509 'popcnt': 'X86_CPUID_FEATURE_ECX_POPCNT',
510 'aes': 'X86_CPUID_FEATURE_ECX_AES',
511 'xsave': 'X86_CPUID_FEATURE_ECX_XSAVE',
512 'avx': 'X86_CPUID_FEATURE_ECX_AVX',
513 'avx2': 'X86_CPUID_STEXT_FEATURE_EBX_AVX2',
514 'f16c': 'X86_CPUID_FEATURE_ECX_F16C',
515 'rdrand': 'X86_CPUID_FEATURE_ECX_RDRAND',
516
517 'axmmx': 'X86_CPUID_AMD_FEATURE_EDX_AXMMX',
518 '3dnowext': 'X86_CPUID_AMD_FEATURE_EDX_3DNOW_EX',
519 '3dnow': 'X86_CPUID_AMD_FEATURE_EDX_3DNOW',
520 'svm': 'X86_CPUID_AMD_FEATURE_ECX_SVM',
521 'cr8l': 'X86_CPUID_AMD_FEATURE_ECX_CR8L',
522 'abm': 'X86_CPUID_AMD_FEATURE_ECX_ABM',
523 'sse4a': 'X86_CPUID_AMD_FEATURE_ECX_SSE4A',
524 '3dnowprf': 'X86_CPUID_AMD_FEATURE_ECX_3DNOWPRF',
525 'xop': 'X86_CPUID_AMD_FEATURE_ECX_XOP',
526 'fma4': 'X86_CPUID_AMD_FEATURE_ECX_FMA4',
527};
528
529## \@ophints values.
530g_kdHints = {
531 'invalid': 'DISOPTYPE_INVALID', ##<
532 'harmless': 'DISOPTYPE_HARMLESS', ##<
533 'controlflow': 'DISOPTYPE_CONTROLFLOW', ##<
534 'potentially_dangerous': 'DISOPTYPE_POTENTIALLY_DANGEROUS', ##<
535 'dangerous': 'DISOPTYPE_DANGEROUS', ##<
536 'portio': 'DISOPTYPE_PORTIO', ##<
537 'privileged': 'DISOPTYPE_PRIVILEGED', ##<
538 'privileged_notrap': 'DISOPTYPE_PRIVILEGED_NOTRAP', ##<
539 'uncond_controlflow': 'DISOPTYPE_UNCOND_CONTROLFLOW', ##<
540 'relative_controlflow': 'DISOPTYPE_RELATIVE_CONTROLFLOW', ##<
541 'cond_controlflow': 'DISOPTYPE_COND_CONTROLFLOW', ##<
542 'interrupt': 'DISOPTYPE_INTERRUPT', ##<
543 'illegal': 'DISOPTYPE_ILLEGAL', ##<
544 'rrm_dangerous': 'DISOPTYPE_RRM_DANGEROUS', ##< Some additional dangerous ones when recompiling raw r0.
545 'rrm_dangerous_16': 'DISOPTYPE_RRM_DANGEROUS_16', ##< Some additional dangerous ones when recompiling 16-bit raw r0.
546 'inhibit_irqs': 'DISOPTYPE_INHIBIT_IRQS', ##< Will or can inhibit irqs (sti, pop ss, mov ss) */
547 'portio_read': 'DISOPTYPE_PORTIO_READ', ##<
548 'portio_write': 'DISOPTYPE_PORTIO_WRITE', ##<
549 'invalid_64': 'DISOPTYPE_INVALID_64', ##< Invalid in 64 bits mode
550 'only_64': 'DISOPTYPE_ONLY_64', ##< Only valid in 64 bits mode
551 'default_64_op_size': 'DISOPTYPE_DEFAULT_64_OP_SIZE', ##< Default 64 bits operand size
552 'forced_64_op_size': 'DISOPTYPE_FORCED_64_OP_SIZE', ##< Forced 64 bits operand size; regardless of prefix bytes
553 'rexb_extends_opreg': 'DISOPTYPE_REXB_EXTENDS_OPREG', ##< REX.B extends the register field in the opcode byte
554 'mod_fixed_11': 'DISOPTYPE_MOD_FIXED_11', ##< modrm.mod is always 11b
555 'forced_32_op_size_x86': 'DISOPTYPE_FORCED_32_OP_SIZE_X86', ##< Forced 32 bits operand size; regardless of prefix bytes
556 ## (only in 16 & 32 bits mode!)
557 'avx': 'DISOPTYPE_AVX', ##< AVX,AVX2,++ instruction. Not implemented yet!
558 'sse': 'DISOPTYPE_SSE', ##< SSE,SSE2,SSE3,++ instruction. Not implemented yet!
559 'mmx': 'DISOPTYPE_MMX', ##< MMX,MMXExt,3DNow,++ instruction. Not implemented yet!
560 'fpu': 'DISOPTYPE_FPU', ##< FPU instruction. Not implemented yet!
561 'ignores_oz_pfx': '', ##< Ignores operand size prefix 66h.
562 'ignores_rexw': '', ##< Ignores REX.W.
563 'ignores_op_sizes': '', ##< Shorthand for "ignores_oz_pfx | ignores_op_sizes".
564 'vex_l_zero': '', ##< VEX.L must be 0.
565 'vex_l_ignored': '', ##< VEX.L is ignored.
566 'vex_v_zero': '', ##< VEX.V must be 0. (generate sub-table?)
567 'lock_allowed': '', ##< Lock prefix allowed.
568};
569
570## \@opxcpttype values (see SDMv2 2.4, 2.7).
571g_kdXcptTypes = {
572 'none': [],
573 '1': [],
574 '2': [],
575 '3': [],
576 '4': [],
577 '4UA': [],
578 '5': [],
579 '5LZ': [], # LZ = VEX.L must be zero.
580 '6': [],
581 '7': [],
582 '7LZ': [],
583 '8': [],
584 '11': [],
585 '12': [],
586 'E1': [],
587 'E1NF': [],
588 'E2': [],
589 'E3': [],
590 'E3NF': [],
591 'E4': [],
592 'E4NF': [],
593 'E5': [],
594 'E5NF': [],
595 'E6': [],
596 'E6NF': [],
597 'E7NF': [],
598 'E9': [],
599 'E9NF': [],
600 'E10': [],
601 'E11': [],
602 'E12': [],
603 'E12NF': [],
604};
605
606
607def _isValidOpcodeByte(sOpcode):
608 """
609 Checks if sOpcode is a valid lower case opcode byte.
610 Returns true/false.
611 """
612 if len(sOpcode) == 4:
613 if sOpcode[:2] == '0x':
614 if sOpcode[2] in '0123456789abcdef':
615 if sOpcode[3] in '0123456789abcdef':
616 return True;
617 return False;
618
619
620class InstructionMap(object):
621 """
622 Instruction map.
623
624 The opcode map provides the lead opcode bytes (empty for the one byte
625 opcode map). An instruction can be member of multiple opcode maps as long
626 as it uses the same opcode value within the map (because of VEX).
627 """
628
629 kdEncodings = {
630 'legacy': [],
631 'vex1': [], ##< VEX or EVEX prefix with vvvvv = 1
632 'vex2': [], ##< VEX or EVEX prefix with vvvvv = 2
633 'vex3': [], ##< VEX or EVEX prefix with vvvvv = 3
634 'xop8': [], ##< XOP prefix with vvvvv = 8
635 'xop9': [], ##< XOP prefix with vvvvv = 9
636 'xop10': [], ##< XOP prefix with vvvvv = 10
637 };
638 ## Selectors.
639 ## 1. The first value is the number of table entries required by a
640 ## decoder or disassembler for this type of selector.
641 ## 2. The second value is how many entries per opcode byte if applicable.
642 kdSelectors = {
643 'byte': [ 256, 1, ], ##< next opcode byte selects the instruction (default).
644 'byte+pfx': [ 1024, 4, ], ##< next opcode byte selects the instruction together with the 0x66, 0xf2 and 0xf3 prefixes.
645 '/r': [ 8, 1, ], ##< modrm.reg selects the instruction.
646 'memreg /r':[ 16, 1, ], ##< modrm.reg and (modrm.mod == 3) selects the instruction.
647 'mod /r': [ 32, 1, ], ##< modrm.reg and modrm.mod selects the instruction.
648 '!11 /r': [ 8, 1, ], ##< modrm.reg selects the instruction with modrm.mod != 0y11.
649 '11 /r': [ 8, 1, ], ##< modrm.reg select the instruction with modrm.mod == 0y11.
650 '11': [ 64, 1, ], ##< modrm.reg and modrm.rm select the instruction with modrm.mod == 0y11.
651 };
652
653 ## Define the subentry number according to the Instruction::sPrefix
654 ## value for 'byte+pfx' selected tables.
655 kiPrefixOrder = {
656 'none': 0,
657 '0x66': 1,
658 '0xf3': 2,
659 '0xf2': 3,
660 };
661
662 def __init__(self, sName, sIemName = None, asLeadOpcodes = None, sSelector = 'byte+pfx',
663 sEncoding = 'legacy', sDisParse = None):
664 assert sSelector in self.kdSelectors;
665 assert sEncoding in self.kdEncodings;
666 if asLeadOpcodes is None:
667 asLeadOpcodes = [];
668 else:
669 for sOpcode in asLeadOpcodes:
670 assert _isValidOpcodeByte(sOpcode);
671 assert sDisParse is None or sDisParse.startswith('IDX_Parse');
672
673 self.sName = sName;
674 self.sIemName = sIemName;
675 self.asLeadOpcodes = asLeadOpcodes; ##< Lead opcode bytes formatted as hex strings like '0x0f'.
676 self.sSelector = sSelector; ##< The member selector, see kdSelectors.
677 self.sEncoding = sEncoding; ##< The encoding, see kdSelectors.
678 self.aoInstructions = [] # type: Instruction
679 self.sDisParse = sDisParse; ##< IDX_ParseXXX.
680
681 def copy(self, sNewName, sPrefixFilter = None):
682 """
683 Copies the table with filtering instruction by sPrefix if not None.
684 """
685 oCopy = InstructionMap(sNewName, sIemName = self.sIemName, asLeadOpcodes = self.asLeadOpcodes,
686 sSelector = 'byte' if sPrefixFilter is not None and self.sSelector == 'byte+pfx'
687 else self.sSelector,
688 sEncoding = self.sEncoding, sDisParse = self.sDisParse);
689 if sPrefixFilter is None:
690 oCopy.aoInstructions = list(self.aoInstructions);
691 else:
692 oCopy.aoInstructions = [oInstr for oInstr in self.aoInstructions if oInstr.sPrefix == sPrefixFilter];
693 return oCopy;
694
695 def getTableSize(self):
696 """
697 Number of table entries. This corresponds directly to the selector.
698 """
699 return self.kdSelectors[self.sSelector][0];
700
701 def getEntriesPerByte(self):
702 """
703 Number of table entries per opcode bytes.
704
705 This only really makes sense for the 'byte' and 'byte+pfx' selectors, for
706 the others it will just return 1.
707 """
708 return self.kdSelectors[self.sSelector][1];
709
710 def getInstructionIndex(self, oInstr):
711 """
712 Returns the table index for the instruction.
713 """
714 bOpcode = oInstr.getOpcodeByte();
715
716 # The byte selectors are simple. We need a full opcode byte and need just return it.
717 if self.sSelector == 'byte':
718 assert oInstr.sOpcode[:2] == '0x' and len(oInstr.sOpcode) == 4, str(oInstr);
719 return bOpcode;
720
721 # The byte + prefix selector is similarly simple, though requires a prefix as well as the full opcode.
722 if self.sSelector == 'byte+pfx':
723 assert oInstr.sOpcode[:2] == '0x' and len(oInstr.sOpcode) == 4, str(oInstr);
724 assert self.kiPrefixOrder.get(oInstr.sPrefix, -16384) >= 0;
725 return bOpcode * 4 + self.kiPrefixOrder.get(oInstr.sPrefix, -16384);
726
727 # The other selectors needs masking and shifting.
728 if self.sSelector == '/r':
729 return (bOpcode >> 3) & 0x7;
730
731 if self.sSelector == 'mod /r':
732 return (bOpcode >> 3) & 0x1f;
733
734 if self.sSelector == 'memreg /r':
735 return ((bOpcode >> 3) & 0x7) | (int((bOpcode >> 6) == 3) << 3);
736
737 if self.sSelector == '!11 /r':
738 assert (bOpcode & 0xc0) != 0xc, str(oInstr);
739 return (bOpcode >> 3) & 0x7;
740
741 if self.sSelector == '11 /r':
742 assert (bOpcode & 0xc0) == 0xc, str(oInstr);
743 return (bOpcode >> 3) & 0x7;
744
745 if self.sSelector == '11':
746 assert (bOpcode & 0xc0) == 0xc, str(oInstr);
747 return bOpcode & 0x3f;
748
749 assert False, self.sSelector;
750 return -1;
751
752 def getInstructionsInTableOrder(self):
753 """
754 Get instructions in table order.
755
756 Returns array of instructions. Normally there is exactly one
757 instruction per entry. However the entry could also be None if
758 not instruction was specified for that opcode value. Or there
759 could be a list of instructions to deal with special encodings
760 where for instance prefix (e.g. REX.W) encodes a different
761 instruction or different CPUs have different instructions or
762 prefixes in the same place.
763 """
764 # Start with empty table.
765 cTable = self.getTableSize();
766 aoTable = [None] * cTable;
767
768 # Insert the instructions.
769 for oInstr in self.aoInstructions:
770 if oInstr.sOpcode:
771 idxOpcode = self.getInstructionIndex(oInstr);
772 assert idxOpcode < cTable, str(idxOpcode);
773
774 oExisting = aoTable[idxOpcode];
775 if oExisting is None:
776 aoTable[idxOpcode] = oInstr;
777 elif not isinstance(oExisting, list):
778 aoTable[idxOpcode] = list([oExisting, oInstr]);
779 else:
780 oExisting.append(oInstr);
781
782 return aoTable;
783
784
785 def getDisasTableName(self):
786 """
787 Returns the disassembler table name for this map.
788 """
789 sName = 'g_aDisas';
790 for sWord in self.sName.split('_'):
791 if sWord == 'm': # suffix indicating modrm.mod==mem
792 sName += '_m';
793 elif sWord == 'r': # suffix indicating modrm.mod==reg
794 sName += '_r';
795 elif len(sWord) == 2 and re.match('^[a-f0-9][a-f0-9]$', sWord):
796 sName += '_' + sWord;
797 else:
798 sWord = sWord.replace('grp', 'Grp');
799 sWord = sWord.replace('map', 'Map');
800 sName += sWord[0].upper() + sWord[1:];
801 return sName;
802
803 def getDisasRangeName(self):
804 """
805 Returns the disassembler table range name for this map.
806 """
807 return self.getDisasTableName().replace('g_aDisas', 'g_Disas') + 'Range';
808
809 def isVexMap(self):
810 """ Returns True if a VEX map. """
811 return self.sEncoding.startswith('vex');
812
813
814class TestType(object):
815 """
816 Test value type.
817
818 This base class deals with integer like values. The fUnsigned constructor
819 parameter indicates the default stance on zero vs sign extending. It is
820 possible to override fUnsigned=True by prefixing the value with '+' or '-'.
821 """
822 def __init__(self, sName, acbSizes = None, fUnsigned = True):
823 self.sName = sName;
824 self.acbSizes = [1, 2, 4, 8, 16, 32] if acbSizes is None else acbSizes; # Normal sizes.
825 self.fUnsigned = fUnsigned;
826
827 class BadValue(Exception):
828 """ Bad value exception. """
829 def __init__(self, sMessage):
830 Exception.__init__(self, sMessage);
831 self.sMessage = sMessage;
832
833 ## For ascii ~ operator.
834 kdHexInv = {
835 '0': 'f',
836 '1': 'e',
837 '2': 'd',
838 '3': 'c',
839 '4': 'b',
840 '5': 'a',
841 '6': '9',
842 '7': '8',
843 '8': '7',
844 '9': '6',
845 'a': '5',
846 'b': '4',
847 'c': '3',
848 'd': '2',
849 'e': '1',
850 'f': '0',
851 };
852
853 def get(self, sValue):
854 """
855 Get the shortest normal sized byte representation of oValue.
856
857 Returns ((fSignExtend, bytearray), ) or ((fSignExtend, bytearray), (fSignExtend, bytearray), ).
858 The latter form is for AND+OR pairs where the first entry is what to
859 AND with the field and the second the one or OR with.
860
861 Raises BadValue if invalid value.
862 """
863 if not sValue:
864 raise TestType.BadValue('empty value');
865
866 # Deal with sign and detect hexadecimal or decimal.
867 fSignExtend = not self.fUnsigned;
868 if sValue[0] == '-' or sValue[0] == '+':
869 fSignExtend = True;
870 fHex = len(sValue) > 3 and sValue[1:3].lower() == '0x';
871 else:
872 fHex = len(sValue) > 2 and sValue[0:2].lower() == '0x';
873
874 # try convert it to long integer.
875 try:
876 iValue = long(sValue, 16 if fHex else 10);
877 except Exception as oXcpt:
878 raise TestType.BadValue('failed to convert "%s" to integer (%s)' % (sValue, oXcpt));
879
880 # Convert the hex string and pad it to a decent value. Negative values
881 # needs to be manually converted to something non-negative (~-n + 1).
882 if iValue >= 0:
883 sHex = hex(iValue);
884 if sys.version_info[0] < 3:
885 assert sHex[-1] == 'L';
886 sHex = sHex[:-1];
887 assert sHex[:2] == '0x';
888 sHex = sHex[2:];
889 else:
890 sHex = hex(-iValue - 1);
891 if sys.version_info[0] < 3:
892 assert sHex[-1] == 'L';
893 sHex = sHex[:-1];
894 assert sHex[:2] == '0x';
895 sHex = ''.join([self.kdHexInv[sDigit] for sDigit in sHex[2:]]);
896 if fSignExtend and sHex[0] not in [ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']:
897 sHex = 'f' + sHex;
898
899 cDigits = len(sHex);
900 if cDigits <= self.acbSizes[-1] * 2:
901 for cb in self.acbSizes:
902 cNaturalDigits = cb * 2;
903 if cDigits <= cNaturalDigits:
904 break;
905 else:
906 cNaturalDigits = self.acbSizes[-1] * 2;
907 cNaturalDigits = int((cDigits + cNaturalDigits - 1) / cNaturalDigits) * cNaturalDigits;
908 assert isinstance(cNaturalDigits, int)
909
910 if cNaturalDigits != cDigits:
911 cNeeded = cNaturalDigits - cDigits;
912 if iValue >= 0:
913 sHex = ('0' * cNeeded) + sHex;
914 else:
915 sHex = ('f' * cNeeded) + sHex;
916
917 # Invert and convert to bytearray and return it.
918 abValue = bytearray([int(sHex[offHex - 2 : offHex], 16) for offHex in range(len(sHex), 0, -2)]);
919
920 return ((fSignExtend, abValue),);
921
922 def validate(self, sValue):
923 """
924 Returns True if value is okay, error message on failure.
925 """
926 try:
927 self.get(sValue);
928 except TestType.BadValue as oXcpt:
929 return oXcpt.sMessage;
930 return True;
931
932 def isAndOrPair(self, sValue):
933 """
934 Checks if sValue is a pair.
935 """
936 _ = sValue;
937 return False;
938
939
940class TestTypeEflags(TestType):
941 """
942 Special value parsing for EFLAGS/RFLAGS/FLAGS.
943 """
944
945 kdZeroValueFlags = { 'nv': 0, 'pl': 0, 'nz': 0, 'na': 0, 'pe': 0, 'nc': 0, 'di': 0, 'up': 0 };
946
947 def __init__(self, sName):
948 TestType.__init__(self, sName, acbSizes = [1, 2, 4, 8], fUnsigned = True);
949
950 def get(self, sValue):
951 fClear = 0;
952 fSet = 0;
953 for sFlag in sValue.split(','):
954 sConstant = g_kdEFlagsMnemonics.get(sFlag, None);
955 if sConstant is None:
956 raise self.BadValue('Unknown flag "%s" in "%s"' % (sFlag, sValue))
957 if sConstant[0] == '!':
958 fClear |= g_kdX86EFlagsConstants[sConstant[1:]];
959 else:
960 fSet |= g_kdX86EFlagsConstants[sConstant];
961
962 aoSet = TestType.get(self, '0x%x' % (fSet,));
963 if fClear != 0:
964 aoClear = TestType.get(self, '%#x' % (fClear,))
965 assert self.isAndOrPair(sValue) is True;
966 return (aoClear[0], aoSet[0]);
967 assert self.isAndOrPair(sValue) is False;
968 return aoSet;
969
970 def isAndOrPair(self, sValue):
971 for sZeroFlag in self.kdZeroValueFlags:
972 if sValue.find(sZeroFlag) >= 0:
973 return True;
974 return False;
975
976class TestTypeFromDict(TestType):
977 """
978 Special value parsing for CR0.
979 """
980
981 kdZeroValueFlags = { 'nv': 0, 'pl': 0, 'nz': 0, 'na': 0, 'pe': 0, 'nc': 0, 'di': 0, 'up': 0 };
982
983 def __init__(self, sName, kdConstantsAndValues, sConstantPrefix):
984 TestType.__init__(self, sName, acbSizes = [1, 2, 4, 8], fUnsigned = True);
985 self.kdConstantsAndValues = kdConstantsAndValues;
986 self.sConstantPrefix = sConstantPrefix;
987
988 def get(self, sValue):
989 fValue = 0;
990 for sFlag in sValue.split(','):
991 fFlagValue = self.kdConstantsAndValues.get(self.sConstantPrefix + sFlag.upper(), None);
992 if fFlagValue is None:
993 raise self.BadValue('Unknown flag "%s" in "%s"' % (sFlag, sValue))
994 fValue |= fFlagValue;
995 return TestType.get(self, '0x%x' % (fValue,));
996
997
998class TestInOut(object):
999 """
1000 One input or output state modifier.
1001
1002 This should be thought as values to modify BS3REGCTX and extended (needs
1003 to be structured) state.
1004 """
1005 ## Assigned operators.
1006 kasOperators = [
1007 '&|=', # Special AND(INV)+OR operator for use with EFLAGS.
1008 '&~=',
1009 '&=',
1010 '|=',
1011 '='
1012 ];
1013 ## Types
1014 kdTypes = {
1015 'uint': TestType('uint', fUnsigned = True),
1016 'int': TestType('int'),
1017 'efl': TestTypeEflags('efl'),
1018 'cr0': TestTypeFromDict('cr0', g_kdX86Cr0Constants, 'X86_CR0_'),
1019 'cr4': TestTypeFromDict('cr4', g_kdX86Cr4Constants, 'X86_CR4_'),
1020 'xcr0': TestTypeFromDict('xcr0', g_kdX86XSaveCConstants, 'XSAVE_C_'),
1021 };
1022 ## CPU context fields.
1023 kdFields = {
1024 # name: ( default type, [both|input|output], )
1025 # Operands.
1026 'op1': ( 'uint', 'both', ), ## \@op1
1027 'op2': ( 'uint', 'both', ), ## \@op2
1028 'op3': ( 'uint', 'both', ), ## \@op3
1029 'op4': ( 'uint', 'both', ), ## \@op4
1030 # Flags.
1031 'efl': ( 'efl', 'both', ),
1032 'efl_undef': ( 'uint', 'output', ),
1033 # 8-bit GPRs.
1034 'al': ( 'uint', 'both', ),
1035 'cl': ( 'uint', 'both', ),
1036 'dl': ( 'uint', 'both', ),
1037 'bl': ( 'uint', 'both', ),
1038 'ah': ( 'uint', 'both', ),
1039 'ch': ( 'uint', 'both', ),
1040 'dh': ( 'uint', 'both', ),
1041 'bh': ( 'uint', 'both', ),
1042 'r8l': ( 'uint', 'both', ),
1043 'r9l': ( 'uint', 'both', ),
1044 'r10l': ( 'uint', 'both', ),
1045 'r11l': ( 'uint', 'both', ),
1046 'r12l': ( 'uint', 'both', ),
1047 'r13l': ( 'uint', 'both', ),
1048 'r14l': ( 'uint', 'both', ),
1049 'r15l': ( 'uint', 'both', ),
1050 # 16-bit GPRs.
1051 'ax': ( 'uint', 'both', ),
1052 'dx': ( 'uint', 'both', ),
1053 'cx': ( 'uint', 'both', ),
1054 'bx': ( 'uint', 'both', ),
1055 'sp': ( 'uint', 'both', ),
1056 'bp': ( 'uint', 'both', ),
1057 'si': ( 'uint', 'both', ),
1058 'di': ( 'uint', 'both', ),
1059 'r8w': ( 'uint', 'both', ),
1060 'r9w': ( 'uint', 'both', ),
1061 'r10w': ( 'uint', 'both', ),
1062 'r11w': ( 'uint', 'both', ),
1063 'r12w': ( 'uint', 'both', ),
1064 'r13w': ( 'uint', 'both', ),
1065 'r14w': ( 'uint', 'both', ),
1066 'r15w': ( 'uint', 'both', ),
1067 # 32-bit GPRs.
1068 'eax': ( 'uint', 'both', ),
1069 'edx': ( 'uint', 'both', ),
1070 'ecx': ( 'uint', 'both', ),
1071 'ebx': ( 'uint', 'both', ),
1072 'esp': ( 'uint', 'both', ),
1073 'ebp': ( 'uint', 'both', ),
1074 'esi': ( 'uint', 'both', ),
1075 'edi': ( 'uint', 'both', ),
1076 'r8d': ( 'uint', 'both', ),
1077 'r9d': ( 'uint', 'both', ),
1078 'r10d': ( 'uint', 'both', ),
1079 'r11d': ( 'uint', 'both', ),
1080 'r12d': ( 'uint', 'both', ),
1081 'r13d': ( 'uint', 'both', ),
1082 'r14d': ( 'uint', 'both', ),
1083 'r15d': ( 'uint', 'both', ),
1084 # 64-bit GPRs.
1085 'rax': ( 'uint', 'both', ),
1086 'rdx': ( 'uint', 'both', ),
1087 'rcx': ( 'uint', 'both', ),
1088 'rbx': ( 'uint', 'both', ),
1089 'rsp': ( 'uint', 'both', ),
1090 'rbp': ( 'uint', 'both', ),
1091 'rsi': ( 'uint', 'both', ),
1092 'rdi': ( 'uint', 'both', ),
1093 'r8': ( 'uint', 'both', ),
1094 'r9': ( 'uint', 'both', ),
1095 'r10': ( 'uint', 'both', ),
1096 'r11': ( 'uint', 'both', ),
1097 'r12': ( 'uint', 'both', ),
1098 'r13': ( 'uint', 'both', ),
1099 'r14': ( 'uint', 'both', ),
1100 'r15': ( 'uint', 'both', ),
1101 # 16-bit, 32-bit or 64-bit registers according to operand size.
1102 'oz.rax': ( 'uint', 'both', ),
1103 'oz.rdx': ( 'uint', 'both', ),
1104 'oz.rcx': ( 'uint', 'both', ),
1105 'oz.rbx': ( 'uint', 'both', ),
1106 'oz.rsp': ( 'uint', 'both', ),
1107 'oz.rbp': ( 'uint', 'both', ),
1108 'oz.rsi': ( 'uint', 'both', ),
1109 'oz.rdi': ( 'uint', 'both', ),
1110 'oz.r8': ( 'uint', 'both', ),
1111 'oz.r9': ( 'uint', 'both', ),
1112 'oz.r10': ( 'uint', 'both', ),
1113 'oz.r11': ( 'uint', 'both', ),
1114 'oz.r12': ( 'uint', 'both', ),
1115 'oz.r13': ( 'uint', 'both', ),
1116 'oz.r14': ( 'uint', 'both', ),
1117 'oz.r15': ( 'uint', 'both', ),
1118 # Control registers.
1119 'cr0': ( 'cr0', 'both', ),
1120 'cr4': ( 'cr4', 'both', ),
1121 'xcr0': ( 'xcr0', 'both', ),
1122 # FPU Registers
1123 'fcw': ( 'uint', 'both', ),
1124 'fsw': ( 'uint', 'both', ),
1125 'ftw': ( 'uint', 'both', ),
1126 'fop': ( 'uint', 'both', ),
1127 'fpuip': ( 'uint', 'both', ),
1128 'fpucs': ( 'uint', 'both', ),
1129 'fpudp': ( 'uint', 'both', ),
1130 'fpuds': ( 'uint', 'both', ),
1131 'mxcsr': ( 'uint', 'both', ),
1132 'st0': ( 'uint', 'both', ),
1133 'st1': ( 'uint', 'both', ),
1134 'st2': ( 'uint', 'both', ),
1135 'st3': ( 'uint', 'both', ),
1136 'st4': ( 'uint', 'both', ),
1137 'st5': ( 'uint', 'both', ),
1138 'st6': ( 'uint', 'both', ),
1139 'st7': ( 'uint', 'both', ),
1140 # MMX registers.
1141 'mm0': ( 'uint', 'both', ),
1142 'mm1': ( 'uint', 'both', ),
1143 'mm2': ( 'uint', 'both', ),
1144 'mm3': ( 'uint', 'both', ),
1145 'mm4': ( 'uint', 'both', ),
1146 'mm5': ( 'uint', 'both', ),
1147 'mm6': ( 'uint', 'both', ),
1148 'mm7': ( 'uint', 'both', ),
1149 # SSE registers.
1150 'xmm0': ( 'uint', 'both', ),
1151 'xmm1': ( 'uint', 'both', ),
1152 'xmm2': ( 'uint', 'both', ),
1153 'xmm3': ( 'uint', 'both', ),
1154 'xmm4': ( 'uint', 'both', ),
1155 'xmm5': ( 'uint', 'both', ),
1156 'xmm6': ( 'uint', 'both', ),
1157 'xmm7': ( 'uint', 'both', ),
1158 'xmm8': ( 'uint', 'both', ),
1159 'xmm9': ( 'uint', 'both', ),
1160 'xmm10': ( 'uint', 'both', ),
1161 'xmm11': ( 'uint', 'both', ),
1162 'xmm12': ( 'uint', 'both', ),
1163 'xmm13': ( 'uint', 'both', ),
1164 'xmm14': ( 'uint', 'both', ),
1165 'xmm15': ( 'uint', 'both', ),
1166 'xmm0.lo': ( 'uint', 'both', ),
1167 'xmm1.lo': ( 'uint', 'both', ),
1168 'xmm2.lo': ( 'uint', 'both', ),
1169 'xmm3.lo': ( 'uint', 'both', ),
1170 'xmm4.lo': ( 'uint', 'both', ),
1171 'xmm5.lo': ( 'uint', 'both', ),
1172 'xmm6.lo': ( 'uint', 'both', ),
1173 'xmm7.lo': ( 'uint', 'both', ),
1174 'xmm8.lo': ( 'uint', 'both', ),
1175 'xmm9.lo': ( 'uint', 'both', ),
1176 'xmm10.lo': ( 'uint', 'both', ),
1177 'xmm11.lo': ( 'uint', 'both', ),
1178 'xmm12.lo': ( 'uint', 'both', ),
1179 'xmm13.lo': ( 'uint', 'both', ),
1180 'xmm14.lo': ( 'uint', 'both', ),
1181 'xmm15.lo': ( 'uint', 'both', ),
1182 'xmm0.hi': ( 'uint', 'both', ),
1183 'xmm1.hi': ( 'uint', 'both', ),
1184 'xmm2.hi': ( 'uint', 'both', ),
1185 'xmm3.hi': ( 'uint', 'both', ),
1186 'xmm4.hi': ( 'uint', 'both', ),
1187 'xmm5.hi': ( 'uint', 'both', ),
1188 'xmm6.hi': ( 'uint', 'both', ),
1189 'xmm7.hi': ( 'uint', 'both', ),
1190 'xmm8.hi': ( 'uint', 'both', ),
1191 'xmm9.hi': ( 'uint', 'both', ),
1192 'xmm10.hi': ( 'uint', 'both', ),
1193 'xmm11.hi': ( 'uint', 'both', ),
1194 'xmm12.hi': ( 'uint', 'both', ),
1195 'xmm13.hi': ( 'uint', 'both', ),
1196 'xmm14.hi': ( 'uint', 'both', ),
1197 'xmm15.hi': ( 'uint', 'both', ),
1198 'xmm0.lo.zx': ( 'uint', 'both', ),
1199 'xmm1.lo.zx': ( 'uint', 'both', ),
1200 'xmm2.lo.zx': ( 'uint', 'both', ),
1201 'xmm3.lo.zx': ( 'uint', 'both', ),
1202 'xmm4.lo.zx': ( 'uint', 'both', ),
1203 'xmm5.lo.zx': ( 'uint', 'both', ),
1204 'xmm6.lo.zx': ( 'uint', 'both', ),
1205 'xmm7.lo.zx': ( 'uint', 'both', ),
1206 'xmm8.lo.zx': ( 'uint', 'both', ),
1207 'xmm9.lo.zx': ( 'uint', 'both', ),
1208 'xmm10.lo.zx': ( 'uint', 'both', ),
1209 'xmm11.lo.zx': ( 'uint', 'both', ),
1210 'xmm12.lo.zx': ( 'uint', 'both', ),
1211 'xmm13.lo.zx': ( 'uint', 'both', ),
1212 'xmm14.lo.zx': ( 'uint', 'both', ),
1213 'xmm15.lo.zx': ( 'uint', 'both', ),
1214 'xmm0.dw0': ( 'uint', 'both', ),
1215 'xmm1.dw0': ( 'uint', 'both', ),
1216 'xmm2.dw0': ( 'uint', 'both', ),
1217 'xmm3.dw0': ( 'uint', 'both', ),
1218 'xmm4.dw0': ( 'uint', 'both', ),
1219 'xmm5.dw0': ( 'uint', 'both', ),
1220 'xmm6.dw0': ( 'uint', 'both', ),
1221 'xmm7.dw0': ( 'uint', 'both', ),
1222 'xmm8.dw0': ( 'uint', 'both', ),
1223 'xmm9.dw0': ( 'uint', 'both', ),
1224 'xmm10.dw0': ( 'uint', 'both', ),
1225 'xmm11.dw0': ( 'uint', 'both', ),
1226 'xmm12.dw0': ( 'uint', 'both', ),
1227 'xmm13.dw0': ( 'uint', 'both', ),
1228 'xmm14.dw0': ( 'uint', 'both', ),
1229 'xmm15_dw0': ( 'uint', 'both', ),
1230 # AVX registers.
1231 'ymm0': ( 'uint', 'both', ),
1232 'ymm1': ( 'uint', 'both', ),
1233 'ymm2': ( 'uint', 'both', ),
1234 'ymm3': ( 'uint', 'both', ),
1235 'ymm4': ( 'uint', 'both', ),
1236 'ymm5': ( 'uint', 'both', ),
1237 'ymm6': ( 'uint', 'both', ),
1238 'ymm7': ( 'uint', 'both', ),
1239 'ymm8': ( 'uint', 'both', ),
1240 'ymm9': ( 'uint', 'both', ),
1241 'ymm10': ( 'uint', 'both', ),
1242 'ymm11': ( 'uint', 'both', ),
1243 'ymm12': ( 'uint', 'both', ),
1244 'ymm13': ( 'uint', 'both', ),
1245 'ymm14': ( 'uint', 'both', ),
1246 'ymm15': ( 'uint', 'both', ),
1247
1248 # Special ones.
1249 'value.xcpt': ( 'uint', 'output', ),
1250 };
1251
1252 def __init__(self, sField, sOp, sValue, sType):
1253 assert sField in self.kdFields;
1254 assert sOp in self.kasOperators;
1255 self.sField = sField;
1256 self.sOp = sOp;
1257 self.sValue = sValue;
1258 self.sType = sType;
1259 assert isinstance(sField, str);
1260 assert isinstance(sOp, str);
1261 assert isinstance(sType, str);
1262 assert isinstance(sValue, str);
1263
1264
1265class TestSelector(object):
1266 """
1267 One selector for an instruction test.
1268 """
1269 ## Selector compare operators.
1270 kasCompareOps = [ '==', '!=' ];
1271 ## Selector variables and their valid values.
1272 kdVariables = {
1273 # Operand size.
1274 'size': {
1275 'o16': 'size_o16',
1276 'o32': 'size_o32',
1277 'o64': 'size_o64',
1278 },
1279 # VEX.L value.
1280 'vex.l': {
1281 '0': 'vexl_0',
1282 '1': 'vexl_1',
1283 },
1284 # Execution ring.
1285 'ring': {
1286 '0': 'ring_0',
1287 '1': 'ring_1',
1288 '2': 'ring_2',
1289 '3': 'ring_3',
1290 '0..2': 'ring_0_thru_2',
1291 '1..3': 'ring_1_thru_3',
1292 },
1293 # Basic code mode.
1294 'codebits': {
1295 '64': 'code_64bit',
1296 '32': 'code_32bit',
1297 '16': 'code_16bit',
1298 },
1299 # cpu modes.
1300 'mode': {
1301 'real': 'mode_real',
1302 'prot': 'mode_prot',
1303 'long': 'mode_long',
1304 'v86': 'mode_v86',
1305 'smm': 'mode_smm',
1306 'vmx': 'mode_vmx',
1307 'svm': 'mode_svm',
1308 },
1309 # paging on/off
1310 'paging': {
1311 'on': 'paging_on',
1312 'off': 'paging_off',
1313 },
1314 # CPU vendor
1315 'vendor': {
1316 'amd': 'vendor_amd',
1317 'intel': 'vendor_intel',
1318 'via': 'vendor_via',
1319 },
1320 };
1321 ## Selector shorthand predicates.
1322 ## These translates into variable expressions.
1323 kdPredicates = {
1324 'o16': 'size==o16',
1325 'o32': 'size==o32',
1326 'o64': 'size==o64',
1327 'ring0': 'ring==0',
1328 '!ring0': 'ring==1..3',
1329 'ring1': 'ring==1',
1330 'ring2': 'ring==2',
1331 'ring3': 'ring==3',
1332 'user': 'ring==3',
1333 'supervisor': 'ring==0..2',
1334 '16-bit': 'codebits==16',
1335 '32-bit': 'codebits==32',
1336 '64-bit': 'codebits==64',
1337 'real': 'mode==real',
1338 'prot': 'mode==prot',
1339 'long': 'mode==long',
1340 'v86': 'mode==v86',
1341 'smm': 'mode==smm',
1342 'vmx': 'mode==vmx',
1343 'svm': 'mode==svm',
1344 'paging': 'paging==on',
1345 '!paging': 'paging==off',
1346 'amd': 'vendor==amd',
1347 '!amd': 'vendor!=amd',
1348 'intel': 'vendor==intel',
1349 '!intel': 'vendor!=intel',
1350 'via': 'vendor==via',
1351 '!via': 'vendor!=via',
1352 };
1353
1354 def __init__(self, sVariable, sOp, sValue):
1355 assert sVariable in self.kdVariables;
1356 assert sOp in self.kasCompareOps;
1357 assert sValue in self.kdVariables[sVariable];
1358 self.sVariable = sVariable;
1359 self.sOp = sOp;
1360 self.sValue = sValue;
1361
1362
1363class InstructionTest(object):
1364 """
1365 Instruction test.
1366 """
1367
1368 def __init__(self, oInstr): # type: (InstructionTest, Instruction)
1369 self.oInstr = oInstr # type: InstructionTest
1370 self.aoInputs = [] # type: list(TestInOut)
1371 self.aoOutputs = [] # type: list(TestInOut)
1372 self.aoSelectors = [] # type: list(TestSelector)
1373
1374 def toString(self, fRepr = False):
1375 """
1376 Converts it to string representation.
1377 """
1378 asWords = [];
1379 if self.aoSelectors:
1380 for oSelector in self.aoSelectors:
1381 asWords.append('%s%s%s' % (oSelector.sVariable, oSelector.sOp, oSelector.sValue,));
1382 asWords.append('/');
1383
1384 for oModifier in self.aoInputs:
1385 asWords.append('%s%s%s:%s' % (oModifier.sField, oModifier.sOp, oModifier.sValue, oModifier.sType,));
1386
1387 asWords.append('->');
1388
1389 for oModifier in self.aoOutputs:
1390 asWords.append('%s%s%s:%s' % (oModifier.sField, oModifier.sOp, oModifier.sValue, oModifier.sType,));
1391
1392 if fRepr:
1393 return '<' + ' '.join(asWords) + '>';
1394 return ' '.join(asWords);
1395
1396 def __str__(self):
1397 """ Provide string represenation. """
1398 return self.toString(False);
1399
1400 def __repr__(self):
1401 """ Provide unambigious string representation. """
1402 return self.toString(True);
1403
1404class Operand(object):
1405 """
1406 Instruction operand.
1407 """
1408
1409 def __init__(self, sWhere, sType):
1410 assert sWhere in g_kdOpLocations, sWhere;
1411 assert sType in g_kdOpTypes, sType;
1412 self.sWhere = sWhere; ##< g_kdOpLocations
1413 self.sType = sType; ##< g_kdOpTypes
1414
1415 def usesModRM(self):
1416 """ Returns True if using some form of ModR/M encoding. """
1417 return self.sType[0] in ['E', 'G', 'M'];
1418
1419
1420
1421class Instruction(object): # pylint: disable=too-many-instance-attributes
1422 """
1423 Instruction.
1424 """
1425
1426 def __init__(self, sSrcFile, iLine):
1427 ## @name Core attributes.
1428 ## @{
1429 self.oParent = None # type: Instruction
1430 self.sMnemonic = None;
1431 self.sBrief = None;
1432 self.asDescSections = [] # type: list(str)
1433 self.aoMaps = [] # type: list(InstructionMap)
1434 self.aoOperands = [] # type: list(Operand)
1435 self.sPrefix = None; ##< Single prefix: None, 'none', 0x66, 0xf3, 0xf2
1436 self.sOpcode = None # type: str
1437 self.sSubOpcode = None # type: str
1438 self.sEncoding = None;
1439 self.asFlTest = None;
1440 self.asFlModify = None;
1441 self.asFlUndefined = None;
1442 self.asFlSet = None;
1443 self.asFlClear = None;
1444 self.dHints = {}; ##< Dictionary of instruction hints, flags, whatnot. (Dictionary for speed; dummy value).
1445 self.sDisEnum = None; ##< OP_XXXX value. Default is based on the uppercased mnemonic.
1446 self.asCpuIds = []; ##< The CPUID feature bit names for this instruction. If multiple, assume AND.
1447 self.asReqFeatures = []; ##< Which features are required to be enabled to run this instruction.
1448 self.aoTests = [] # type: list(InstructionTest)
1449 self.sMinCpu = None; ##< Indicates the minimum CPU required for the instruction. Not set when oCpuExpr is.
1450 self.oCpuExpr = None; ##< Some CPU restriction expression...
1451 self.sGroup = None;
1452 self.fUnused = False; ##< Unused instruction.
1453 self.fInvalid = False; ##< Invalid instruction (like UD2).
1454 self.sInvalidStyle = None; ##< Invalid behviour style (g_kdInvalidStyles),
1455 self.sXcptType = None; ##< Exception type (g_kdXcptTypes).
1456 ## @}
1457
1458 ## @name Implementation attributes.
1459 ## @{
1460 self.sStats = None;
1461 self.sFunction = None;
1462 self.fStub = False;
1463 self.fUdStub = False;
1464 ## @}
1465
1466 ## @name Decoding info
1467 ## @{
1468 self.sSrcFile = sSrcFile;
1469 self.iLineCreated = iLine;
1470 self.iLineCompleted = None;
1471 self.cOpTags = 0;
1472 self.iLineFnIemOpMacro = -1;
1473 self.iLineMnemonicMacro = -1;
1474 ## @}
1475
1476 ## @name Intermediate input fields.
1477 ## @{
1478 self.sRawDisOpNo = None;
1479 self.asRawDisParams = [];
1480 self.sRawIemOpFlags = None;
1481 self.sRawOldOpcodes = None;
1482 self.asCopyTests = [];
1483 ## @}
1484
1485 def toString(self, fRepr = False):
1486 """ Turn object into a string. """
1487 aasFields = [];
1488
1489 aasFields.append(['opcode', self.sOpcode]);
1490 if self.sPrefix:
1491 aasFields.append(['prefix', self.sPrefix]);
1492 aasFields.append(['mnemonic', self.sMnemonic]);
1493 for iOperand, oOperand in enumerate(self.aoOperands):
1494 aasFields.append(['op%u' % (iOperand + 1,), '%s:%s' % (oOperand.sWhere, oOperand.sType,)]);
1495 if self.aoMaps: aasFields.append(['maps', ','.join([oMap.sName for oMap in self.aoMaps])]);
1496 aasFields.append(['encoding', self.sEncoding]);
1497 if self.dHints: aasFields.append(['hints', ','.join(self.dHints.keys())]);
1498 aasFields.append(['disenum', self.sDisEnum]);
1499 if self.asCpuIds: aasFields.append(['cpuid', ','.join(self.asCpuIds)]);
1500 aasFields.append(['group', self.sGroup]);
1501 if self.fUnused: aasFields.append(['unused', 'True']);
1502 if self.fInvalid: aasFields.append(['invalid', 'True']);
1503 aasFields.append(['invlstyle', self.sInvalidStyle]);
1504 aasFields.append(['fltest', self.asFlTest]);
1505 aasFields.append(['flmodify', self.asFlModify]);
1506 aasFields.append(['flundef', self.asFlUndefined]);
1507 aasFields.append(['flset', self.asFlSet]);
1508 aasFields.append(['flclear', self.asFlClear]);
1509 aasFields.append(['mincpu', self.sMinCpu]);
1510 aasFields.append(['stats', self.sStats]);
1511 aasFields.append(['sFunction', self.sFunction]);
1512 if self.fStub: aasFields.append(['fStub', 'True']);
1513 if self.fUdStub: aasFields.append(['fUdStub', 'True']);
1514 if self.cOpTags: aasFields.append(['optags', str(self.cOpTags)]);
1515 if self.iLineFnIemOpMacro != -1: aasFields.append(['FNIEMOP_XXX', str(self.iLineFnIemOpMacro)]);
1516 if self.iLineMnemonicMacro != -1: aasFields.append(['IEMOP_MNEMMONICn', str(self.iLineMnemonicMacro)]);
1517
1518 sRet = '<' if fRepr else '';
1519 for sField, sValue in aasFields:
1520 if sValue is not None:
1521 if len(sRet) > 1:
1522 sRet += '; ';
1523 sRet += '%s=%s' % (sField, sValue,);
1524 if fRepr:
1525 sRet += '>';
1526
1527 return sRet;
1528
1529 def __str__(self):
1530 """ Provide string represenation. """
1531 return self.toString(False);
1532
1533 def __repr__(self):
1534 """ Provide unambigious string representation. """
1535 return self.toString(True);
1536
1537 def copy(self, oMap = None, sOpcode = None, sSubOpcode = None, sPrefix = None):
1538 """
1539 Makes a copy of the object for the purpose of putting in a different map
1540 or a different place in the current map.
1541 """
1542 oCopy = Instruction(self.sSrcFile, self.iLineCreated);
1543
1544 oCopy.oParent = self;
1545 oCopy.sMnemonic = self.sMnemonic;
1546 oCopy.sBrief = self.sBrief;
1547 oCopy.asDescSections = list(self.asDescSections);
1548 oCopy.aoMaps = [oMap,] if oMap else list(self.aoMaps);
1549 oCopy.aoOperands = list(self.aoOperands); ## Deeper copy?
1550 oCopy.sPrefix = sPrefix if sPrefix else self.sPrefix;
1551 oCopy.sOpcode = sOpcode if sOpcode else self.sOpcode;
1552 oCopy.sSubOpcode = sSubOpcode if sSubOpcode else self.sSubOpcode;
1553 oCopy.sEncoding = self.sEncoding;
1554 oCopy.asFlTest = self.asFlTest;
1555 oCopy.asFlModify = self.asFlModify;
1556 oCopy.asFlUndefined = self.asFlUndefined;
1557 oCopy.asFlSet = self.asFlSet;
1558 oCopy.asFlClear = self.asFlClear;
1559 oCopy.dHints = dict(self.dHints);
1560 oCopy.sDisEnum = self.sDisEnum;
1561 oCopy.asCpuIds = list(self.asCpuIds);
1562 oCopy.asReqFeatures = list(self.asReqFeatures);
1563 oCopy.aoTests = list(self.aoTests); ## Deeper copy?
1564 oCopy.sMinCpu = self.sMinCpu;
1565 oCopy.oCpuExpr = self.oCpuExpr;
1566 oCopy.sGroup = self.sGroup;
1567 oCopy.fUnused = self.fUnused;
1568 oCopy.fInvalid = self.fInvalid;
1569 oCopy.sInvalidStyle = self.sInvalidStyle;
1570 oCopy.sXcptType = self.sXcptType;
1571
1572 oCopy.sStats = self.sStats;
1573 oCopy.sFunction = self.sFunction;
1574 oCopy.fStub = self.fStub;
1575 oCopy.fUdStub = self.fUdStub;
1576
1577 oCopy.iLineCompleted = self.iLineCompleted;
1578 oCopy.cOpTags = self.cOpTags;
1579 oCopy.iLineFnIemOpMacro = self.iLineFnIemOpMacro;
1580 oCopy.iLineMnemonicMacro = self.iLineMnemonicMacro;
1581
1582 oCopy.sRawDisOpNo = self.sRawDisOpNo;
1583 oCopy.asRawDisParams = list(self.asRawDisParams);
1584 oCopy.sRawIemOpFlags = self.sRawIemOpFlags;
1585 oCopy.sRawOldOpcodes = self.sRawOldOpcodes;
1586 oCopy.asCopyTests = list(self.asCopyTests);
1587
1588 return oCopy;
1589
1590 def getOpcodeByte(self):
1591 """
1592 Decodes sOpcode into a byte range integer value.
1593 Raises exception if sOpcode is None or invalid.
1594 """
1595 if self.sOpcode is None:
1596 raise Exception('No opcode byte for %s!' % (self,));
1597 sOpcode = str(self.sOpcode); # pylint type confusion workaround.
1598
1599 # Full hex byte form.
1600 if sOpcode[:2] == '0x':
1601 return int(sOpcode, 16);
1602
1603 # The /r form:
1604 if len(sOpcode) == 2 and sOpcode[0] == '/' and sOpcode[1].isdigit():
1605 return int(sOpcode[1:]) << 3;
1606
1607 # The 11/r form:
1608 if len(sOpcode) == 4 and sOpcode.startswith('11/') and sOpcode[-1].isdigit():
1609 return (int(sOpcode[-1:]) << 3) | 0xc0;
1610
1611 # The !11/r form (returns mod=1):
1612 ## @todo this doesn't really work...
1613 if len(sOpcode) == 5 and sOpcode.startswith('!11/') and sOpcode[-1].isdigit():
1614 return (int(sOpcode[-1:]) << 3) | 0x80;
1615
1616 raise Exception('unsupported opcode byte spec "%s" for %s' % (sOpcode, self,));
1617
1618 @staticmethod
1619 def _flagsToIntegerMask(asFlags):
1620 """
1621 Returns the integer mask value for asFlags.
1622 """
1623 uRet = 0;
1624 if asFlags:
1625 for sFlag in asFlags:
1626 sConstant = g_kdEFlagsMnemonics[sFlag];
1627 assert sConstant[0] != '!', sConstant
1628 uRet |= g_kdX86EFlagsConstants[sConstant];
1629 return uRet;
1630
1631 def getTestedFlagsMask(self):
1632 """ Returns asFlTest into a integer mask value """
1633 return self._flagsToIntegerMask(self.asFlTest);
1634
1635 def getModifiedFlagsMask(self):
1636 """ Returns asFlModify into a integer mask value """
1637 return self._flagsToIntegerMask(self.asFlModify);
1638
1639 def getUndefinedFlagsMask(self):
1640 """ Returns asFlUndefined into a integer mask value """
1641 return self._flagsToIntegerMask(self.asFlUndefined);
1642
1643 def getSetFlagsMask(self):
1644 """ Returns asFlSet into a integer mask value """
1645 return self._flagsToIntegerMask(self.asFlSet);
1646
1647 def getClearedFlagsMask(self):
1648 """ Returns asFlClear into a integer mask value """
1649 return self._flagsToIntegerMask(self.asFlClear);
1650
1651 def onlyInVexMaps(self):
1652 """ Returns True if only in VEX maps, otherwise False. (No maps -> False) """
1653 if not self.aoMaps:
1654 return False;
1655 for oMap in self.aoMaps:
1656 if not oMap.isVexMap():
1657 return False;
1658 return True;
1659
1660
1661
1662## All the instructions.
1663g_aoAllInstructions = [] # type: list(Instruction)
1664
1665## All the instructions indexed by statistics name (opstat).
1666g_dAllInstructionsByStat = {} # type: dict(Instruction)
1667
1668## All the instructions indexed by function name (opfunction).
1669g_dAllInstructionsByFunction = {} # type: dict(list(Instruction))
1670
1671## Instructions tagged by oponlytest
1672g_aoOnlyTestInstructions = [] # type: list(Instruction)
1673
1674## Instruction maps.
1675g_aoInstructionMaps = [
1676 InstructionMap('one', 'g_apfnOneByteMap', sSelector = 'byte'),
1677 InstructionMap('grp1_80', asLeadOpcodes = ['0x80',], sSelector = '/r'),
1678 InstructionMap('grp1_81', asLeadOpcodes = ['0x81',], sSelector = '/r'),
1679 InstructionMap('grp1_82', asLeadOpcodes = ['0x82',], sSelector = '/r'),
1680 InstructionMap('grp1_83', asLeadOpcodes = ['0x83',], sSelector = '/r'),
1681 InstructionMap('grp1a', asLeadOpcodes = ['0x8f',], sSelector = '/r'),
1682 InstructionMap('grp2_c0', asLeadOpcodes = ['0xc0',], sSelector = '/r'),
1683 InstructionMap('grp2_c1', asLeadOpcodes = ['0xc1',], sSelector = '/r'),
1684 InstructionMap('grp2_d0', asLeadOpcodes = ['0xd0',], sSelector = '/r'),
1685 InstructionMap('grp2_d1', asLeadOpcodes = ['0xd1',], sSelector = '/r'),
1686 InstructionMap('grp2_d2', asLeadOpcodes = ['0xd2',], sSelector = '/r'),
1687 InstructionMap('grp2_d3', asLeadOpcodes = ['0xd3',], sSelector = '/r'),
1688 ## @todo g_apfnEscF1_E0toFF
1689 InstructionMap('grp3_f6', asLeadOpcodes = ['0xf6',], sSelector = '/r'),
1690 InstructionMap('grp3_f7', asLeadOpcodes = ['0xf7',], sSelector = '/r'),
1691 InstructionMap('grp4', asLeadOpcodes = ['0xfe',], sSelector = '/r'),
1692 InstructionMap('grp5', asLeadOpcodes = ['0xff',], sSelector = '/r'),
1693 InstructionMap('grp11_c6_m', asLeadOpcodes = ['0xc6',], sSelector = '!11 /r'),
1694 InstructionMap('grp11_c6_r', asLeadOpcodes = ['0xc6',], sSelector = '11'), # xabort
1695 InstructionMap('grp11_c7_m', asLeadOpcodes = ['0xc7',], sSelector = '!11 /r'),
1696 InstructionMap('grp11_c7_r', asLeadOpcodes = ['0xc7',], sSelector = '11'), # xbegin
1697
1698 InstructionMap('two0f', 'g_apfnTwoByteMap', asLeadOpcodes = ['0x0f',], sDisParse = 'IDX_ParseTwoByteEsc'),
1699 InstructionMap('grp6', 'g_apfnGroup6', asLeadOpcodes = ['0x0f', '0x00',], sSelector = '/r'),
1700 InstructionMap('grp7_m', 'g_apfnGroup7Mem', asLeadOpcodes = ['0x0f', '0x01',], sSelector = '!11 /r'),
1701 InstructionMap('grp7_r', asLeadOpcodes = ['0x0f', '0x01',], sSelector = '11'),
1702 InstructionMap('grp8', asLeadOpcodes = ['0x0f', '0xba',], sSelector = '/r'),
1703 InstructionMap('grp9', 'g_apfnGroup9RegReg', asLeadOpcodes = ['0x0f', '0xc7',], sSelector = 'mod /r'),
1704 ## @todo What about g_apfnGroup9MemReg?
1705 InstructionMap('grp10', None, asLeadOpcodes = ['0x0f', '0xb9',], sSelector = '/r'), # UD1 /w modr/m
1706 InstructionMap('grp12', 'g_apfnGroup12RegReg', asLeadOpcodes = ['0x0f', '0x71',], sSelector = 'mod /r'),
1707 InstructionMap('grp13', 'g_apfnGroup13RegReg', asLeadOpcodes = ['0x0f', '0x72',], sSelector = 'mod /r'),
1708 InstructionMap('grp14', 'g_apfnGroup14RegReg', asLeadOpcodes = ['0x0f', '0x73',], sSelector = 'mod /r'),
1709 InstructionMap('grp15', 'g_apfnGroup15MemReg', asLeadOpcodes = ['0x0f', '0xae',], sSelector = 'memreg /r'),
1710 ## @todo What about g_apfnGroup15RegReg?
1711 InstructionMap('grp16', asLeadOpcodes = ['0x0f', '0x18',], sSelector = 'mod /r'),
1712 InstructionMap('grpA17', asLeadOpcodes = ['0x0f', '0x78',], sSelector = '/r'), # AMD: EXTRQ weirdness
1713 InstructionMap('grpP', asLeadOpcodes = ['0x0f', '0x0d',], sSelector = '/r'), # AMD: prefetch
1714
1715 InstructionMap('three0f38', 'g_apfnThreeByte0f38', asLeadOpcodes = ['0x0f', '0x38',]),
1716 InstructionMap('three0f3a', 'g_apfnThreeByte0f3a', asLeadOpcodes = ['0x0f', '0x3a',]),
1717
1718 InstructionMap('vexmap1', 'g_apfnVexMap1', sEncoding = 'vex1'),
1719 InstructionMap('vexgrp12', 'g_apfnVexGroup12RegReg', sEncoding = 'vex1', asLeadOpcodes = ['0x71',], sSelector = 'mod /r'),
1720 InstructionMap('vexgrp13', 'g_apfnVexGroup13RegReg', sEncoding = 'vex1', asLeadOpcodes = ['0x72',], sSelector = 'mod /r'),
1721 InstructionMap('vexgrp14', 'g_apfnVexGroup14RegReg', sEncoding = 'vex1', asLeadOpcodes = ['0x73',], sSelector = 'mod /r'),
1722 InstructionMap('vexgrp15', 'g_apfnVexGroup15MemReg', sEncoding = 'vex1', asLeadOpcodes = ['0xae',], sSelector = 'memreg /r'),
1723 InstructionMap('vexgrp17', 'g_apfnVexGroup17_f3', sEncoding = 'vex1', asLeadOpcodes = ['0xf3',], sSelector = '/r'),
1724
1725 InstructionMap('vexmap2', 'g_apfnVexMap2', sEncoding = 'vex2'),
1726 InstructionMap('vexmap3', 'g_apfnVexMap3', sEncoding = 'vex3'),
1727
1728 InstructionMap('3dnow', asLeadOpcodes = ['0x0f', '0x0f',]),
1729 InstructionMap('xopmap8', sEncoding = 'xop8'),
1730 InstructionMap('xopmap9', sEncoding = 'xop9'),
1731 InstructionMap('xopgrp1', sEncoding = 'xop9', asLeadOpcodes = ['0x01'], sSelector = '/r'),
1732 InstructionMap('xopgrp2', sEncoding = 'xop9', asLeadOpcodes = ['0x02'], sSelector = '/r'),
1733 InstructionMap('xopgrp3', sEncoding = 'xop9', asLeadOpcodes = ['0x12'], sSelector = '/r'),
1734 InstructionMap('xopmap10', sEncoding = 'xop10'),
1735 InstructionMap('xopgrp4', sEncoding = 'xop10', asLeadOpcodes = ['0x12'], sSelector = '/r'),
1736];
1737g_dInstructionMaps = { oMap.sName: oMap for oMap in g_aoInstructionMaps };
1738g_dInstructionMapsByIemName = { oMap.sIemName: oMap for oMap in g_aoInstructionMaps };
1739
1740
1741
1742class ParserException(Exception):
1743 """ Parser exception """
1744 def __init__(self, sMessage):
1745 Exception.__init__(self, sMessage);
1746
1747
1748class SimpleParser(object):
1749 """
1750 Parser of IEMAllInstruction*.cpp.h instruction specifications.
1751 """
1752
1753 ## @name Parser state.
1754 ## @{
1755 kiCode = 0;
1756 kiCommentMulti = 1;
1757 ## @}
1758
1759 def __init__(self, sSrcFile, asLines, sDefaultMap):
1760 self.sSrcFile = sSrcFile;
1761 self.asLines = asLines;
1762 self.iLine = 0;
1763 self.iState = self.kiCode;
1764 self.sComment = '';
1765 self.iCommentLine = 0;
1766 self.aoCurInstrs = [];
1767
1768 assert sDefaultMap in g_dInstructionMaps;
1769 self.oDefaultMap = g_dInstructionMaps[sDefaultMap];
1770
1771 self.cTotalInstr = 0;
1772 self.cTotalStubs = 0;
1773 self.cTotalTagged = 0;
1774
1775 self.oReMacroName = re.compile('^[A-Za-z_][A-Za-z0-9_]*$');
1776 self.oReMnemonic = re.compile('^[A-Za-z_][A-Za-z0-9_]*$');
1777 self.oReStatsName = re.compile('^[A-Za-z_][A-Za-z0-9_]*$');
1778 self.oReFunctionName= re.compile('^iemOp_[A-Za-z_][A-Za-z0-9_]*$');
1779 self.oReGroupName = re.compile('^og_[a-z0-9]+(|_[a-z0-9]+|_[a-z0-9]+_[a-z0-9]+)$');
1780 self.oReDisEnum = re.compile('^OP_[A-Z0-9_]+$');
1781 self.oReFunTable = re.compile('^(IEM_STATIC|static) +const +PFNIEMOP +g_apfn[A-Za-z0-9_]+ *\[ *\d* *\] *= *$');
1782 self.oReComment = re.compile('//.*?$|/\*.*?\*/'); ## Full comments.
1783 self.fDebug = True;
1784
1785 self.dTagHandlers = {
1786 '@opbrief': self.parseTagOpBrief,
1787 '@opdesc': self.parseTagOpDesc,
1788 '@opmnemonic': self.parseTagOpMnemonic,
1789 '@op1': self.parseTagOpOperandN,
1790 '@op2': self.parseTagOpOperandN,
1791 '@op3': self.parseTagOpOperandN,
1792 '@op4': self.parseTagOpOperandN,
1793 '@oppfx': self.parseTagOpPfx,
1794 '@opmaps': self.parseTagOpMaps,
1795 '@opcode': self.parseTagOpcode,
1796 '@opcodesub': self.parseTagOpcodeSub,
1797 '@openc': self.parseTagOpEnc,
1798 '@opfltest': self.parseTagOpEFlags,
1799 '@opflmodify': self.parseTagOpEFlags,
1800 '@opflundef': self.parseTagOpEFlags,
1801 '@opflset': self.parseTagOpEFlags,
1802 '@opflclear': self.parseTagOpEFlags,
1803 '@ophints': self.parseTagOpHints,
1804 '@opdisenum': self.parseTagOpDisEnum,
1805 '@opmincpu': self.parseTagOpMinCpu,
1806 '@opcpuid': self.parseTagOpCpuId,
1807 '@opgroup': self.parseTagOpGroup,
1808 '@opunused': self.parseTagOpUnusedInvalid,
1809 '@opinvalid': self.parseTagOpUnusedInvalid,
1810 '@opinvlstyle': self.parseTagOpUnusedInvalid,
1811 '@optest': self.parseTagOpTest,
1812 '@optestign': self.parseTagOpTestIgnore,
1813 '@optestignore': self.parseTagOpTestIgnore,
1814 '@opcopytests': self.parseTagOpCopyTests,
1815 '@oponly': self.parseTagOpOnlyTest,
1816 '@oponlytest': self.parseTagOpOnlyTest,
1817 '@opxcpttype': self.parseTagOpXcptType,
1818 '@opstats': self.parseTagOpStats,
1819 '@opfunction': self.parseTagOpFunction,
1820 '@opdone': self.parseTagOpDone,
1821 };
1822 for i in range(48):
1823 self.dTagHandlers['@optest%u' % (i,)] = self.parseTagOpTestNum;
1824 self.dTagHandlers['@optest[%u]' % (i,)] = self.parseTagOpTestNum;
1825
1826 self.asErrors = [];
1827
1828 def raiseError(self, sMessage):
1829 """
1830 Raise error prefixed with the source and line number.
1831 """
1832 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iLine, sMessage,));
1833
1834 def raiseCommentError(self, iLineInComment, sMessage):
1835 """
1836 Similar to raiseError, but the line number is iLineInComment + self.iCommentLine.
1837 """
1838 raise ParserException("%s:%d: error: %s" % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
1839
1840 def error(self, sMessage):
1841 """
1842 Adds an error.
1843 returns False;
1844 """
1845 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iLine, sMessage,));
1846 return False;
1847
1848 def errorOnLine(self, iLine, sMessage):
1849 """
1850 Adds an error.
1851 returns False;
1852 """
1853 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, iLine, sMessage,));
1854 return False;
1855
1856 def errorComment(self, iLineInComment, sMessage):
1857 """
1858 Adds a comment error.
1859 returns False;
1860 """
1861 self.asErrors.append(u'%s:%d: error: %s\n' % (self.sSrcFile, self.iCommentLine + iLineInComment, sMessage,));
1862 return False;
1863
1864 def printErrors(self):
1865 """
1866 Print the errors to stderr.
1867 Returns number of errors.
1868 """
1869 if self.asErrors:
1870 sys.stderr.write(u''.join(self.asErrors));
1871 return len(self.asErrors);
1872
1873 def debug(self, sMessage):
1874 """
1875 For debugging.
1876 """
1877 if self.fDebug:
1878 print('debug: %s' % (sMessage,));
1879
1880 def stripComments(self, sLine):
1881 """
1882 Returns sLine with comments stripped.
1883
1884 Complains if traces of incomplete multi-line comments are encountered.
1885 """
1886 sLine = self.oReComment.sub(" ", sLine);
1887 if sLine.find('/*') >= 0 or sLine.find('*/') >= 0:
1888 self.error('Unexpected multi-line comment will not be handled correctly. Please simplify.');
1889 return sLine;
1890
1891 def parseFunctionTable(self, sLine):
1892 """
1893 Parses a PFNIEMOP table, updating/checking the @oppfx value.
1894
1895 Note! Updates iLine as it consumes the whole table.
1896 """
1897
1898 #
1899 # Extract the table name.
1900 #
1901 sName = re.search(' *([a-zA-Z_0-9]+) *\[', sLine).group(1);
1902 oMap = g_dInstructionMapsByIemName.get(sName);
1903 if not oMap:
1904 self.debug('No map for PFNIEMOP table: %s' % (sName,));
1905 oMap = self.oDefaultMap; # This is wrong wrong wrong.
1906
1907 #
1908 # All but the g_apfnOneByteMap & g_apfnEscF1_E0toFF tables uses four
1909 # entries per byte:
1910 # no prefix, 066h prefix, f3h prefix, f2h prefix
1911 # Those tables has 256 & 32 entries respectively.
1912 #
1913 cEntriesPerByte = 4;
1914 cValidTableLength = 1024;
1915 asPrefixes = ('none', '0x66', '0xf3', '0xf2');
1916
1917 oEntriesMatch = re.search('\[ *(256|32) *\]', sLine);
1918 if oEntriesMatch:
1919 cEntriesPerByte = 1;
1920 cValidTableLength = int(oEntriesMatch.group(1));
1921 asPrefixes = (None,);
1922
1923 #
1924 # The next line should be '{' and nothing else.
1925 #
1926 if self.iLine >= len(self.asLines) or not re.match('^ *{ *$', self.asLines[self.iLine]):
1927 return self.errorOnLine(self.iLine + 1, 'Expected lone "{" on line following PFNIEMOP table %s start' % (sName, ));
1928 self.iLine += 1;
1929
1930 #
1931 # Parse till we find the end of the table.
1932 #
1933 iEntry = 0;
1934 while self.iLine < len(self.asLines):
1935 # Get the next line and strip comments and spaces (assumes no
1936 # multi-line comments).
1937 sLine = self.asLines[self.iLine];
1938 self.iLine += 1;
1939 sLine = self.stripComments(sLine).strip();
1940
1941 # Split the line up into entries, expanding IEMOP_X4 usage.
1942 asEntries = sLine.split(',');
1943 for i in range(len(asEntries) - 1, -1, -1):
1944 sEntry = asEntries[i].strip();
1945 if sEntry.startswith('IEMOP_X4(') and sEntry[-1] == ')':
1946 sEntry = (sEntry[len('IEMOP_X4('):-1]).strip();
1947 asEntries.insert(i + 1, sEntry);
1948 asEntries.insert(i + 1, sEntry);
1949 asEntries.insert(i + 1, sEntry);
1950 if sEntry:
1951 asEntries[i] = sEntry;
1952 else:
1953 del asEntries[i];
1954
1955 # Process the entries.
1956 for sEntry in asEntries:
1957 if sEntry in ('};', '}'):
1958 if iEntry != cValidTableLength:
1959 return self.error('Wrong table length for %s: %#x, expected %#x' % (sName, iEntry, cValidTableLength, ));
1960 return True;
1961 if sEntry.startswith('iemOp_Invalid'):
1962 pass; # skip
1963 else:
1964 # Look up matching instruction by function.
1965 sPrefix = asPrefixes[iEntry % cEntriesPerByte];
1966 sOpcode = '%#04x' % (iEntry // cEntriesPerByte);
1967 aoInstr = g_dAllInstructionsByFunction.get(sEntry);
1968 if aoInstr:
1969 if not isinstance(aoInstr, list):
1970 aoInstr = [aoInstr,];
1971 oInstr = None;
1972 for oCurInstr in aoInstr:
1973 if oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix == sPrefix:
1974 pass;
1975 elif oCurInstr.sOpcode == sOpcode and oCurInstr.sPrefix is None:
1976 oCurInstr.sPrefix = sPrefix;
1977 elif oCurInstr.sOpcode is None and oCurInstr.sPrefix is None:
1978 oCurInstr.sOpcode = sOpcode;
1979 oCurInstr.sPrefix = sPrefix;
1980 else:
1981 continue;
1982 oInstr = oCurInstr;
1983 break;
1984 if not oInstr:
1985 oInstr = aoInstr[0].copy(oMap = oMap, sOpcode = sOpcode, sPrefix = sPrefix);
1986 aoInstr.append(oInstr);
1987 g_dAllInstructionsByFunction[sEntry] = aoInstr;
1988 g_aoAllInstructions.append(oInstr);
1989 oMap.aoInstructions.append(oInstr);
1990 else:
1991 self.debug('Function "%s", entry %#04x / byte %#04x in %s, is not associated with an instruction.'
1992 % (sEntry, iEntry, iEntry // cEntriesPerByte, sName,));
1993 iEntry += 1;
1994
1995 return self.error('Unexpected end of file in PFNIEMOP table');
1996
1997 def addInstruction(self, iLine = None):
1998 """
1999 Adds an instruction.
2000 """
2001 oInstr = Instruction(self.sSrcFile, self.iLine if iLine is None else iLine);
2002 g_aoAllInstructions.append(oInstr);
2003 self.aoCurInstrs.append(oInstr);
2004 return oInstr;
2005
2006 def deriveMnemonicAndOperandsFromStats(self, oInstr, sStats):
2007 """
2008 Derives the mnemonic and operands from a IEM stats base name like string.
2009 """
2010 if oInstr.sMnemonic is None:
2011 asWords = sStats.split('_');
2012 oInstr.sMnemonic = asWords[0].lower();
2013 if len(asWords) > 1 and not oInstr.aoOperands:
2014 for sType in asWords[1:]:
2015 if sType in g_kdOpTypes:
2016 oInstr.aoOperands.append(Operand(g_kdOpTypes[sType][1], sType));
2017 else:
2018 #return self.error('unknown operand type: %s (instruction: %s)' % (sType, oInstr))
2019 return False;
2020 return True;
2021
2022 def doneInstructionOne(self, oInstr, iLine):
2023 """
2024 Complete the parsing by processing, validating and expanding raw inputs.
2025 """
2026 assert oInstr.iLineCompleted is None;
2027 oInstr.iLineCompleted = iLine;
2028
2029 #
2030 # Specified instructions.
2031 #
2032 if oInstr.cOpTags > 0:
2033 if oInstr.sStats is None:
2034 pass;
2035
2036 #
2037 # Unspecified legacy stuff. We generally only got a few things to go on here.
2038 # /** Opcode 0x0f 0x00 /0. */
2039 # FNIEMOPRM_DEF(iemOp_Grp6_sldt)
2040 #
2041 else:
2042 #if oInstr.sRawOldOpcodes:
2043 #
2044 #if oInstr.sMnemonic:
2045 pass;
2046
2047 #
2048 # Common defaults.
2049 #
2050
2051 # Guess mnemonic and operands from stats if the former is missing.
2052 if oInstr.sMnemonic is None:
2053 if oInstr.sStats is not None:
2054 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sStats);
2055 elif oInstr.sFunction is not None:
2056 self.deriveMnemonicAndOperandsFromStats(oInstr, oInstr.sFunction.replace('iemOp_', ''));
2057
2058 # Derive the disassembler op enum constant from the mnemonic.
2059 if oInstr.sDisEnum is None and oInstr.sMnemonic is not None:
2060 oInstr.sDisEnum = 'OP_' + oInstr.sMnemonic.upper();
2061
2062 # Derive the IEM statistics base name from mnemonic and operand types.
2063 if oInstr.sStats is None:
2064 if oInstr.sFunction is not None:
2065 oInstr.sStats = oInstr.sFunction.replace('iemOp_', '');
2066 elif oInstr.sMnemonic is not None:
2067 oInstr.sStats = oInstr.sMnemonic;
2068 for oOperand in oInstr.aoOperands:
2069 if oOperand.sType:
2070 oInstr.sStats += '_' + oOperand.sType;
2071
2072 # Derive the IEM function name from mnemonic and operand types.
2073 if oInstr.sFunction is None:
2074 if oInstr.sMnemonic is not None:
2075 oInstr.sFunction = 'iemOp_' + oInstr.sMnemonic;
2076 for oOperand in oInstr.aoOperands:
2077 if oOperand.sType:
2078 oInstr.sFunction += '_' + oOperand.sType;
2079 elif oInstr.sStats:
2080 oInstr.sFunction = 'iemOp_' + oInstr.sStats;
2081
2082 #
2083 # Apply default map and then add the instruction to all it's groups.
2084 #
2085 if not oInstr.aoMaps:
2086 oInstr.aoMaps = [ self.oDefaultMap, ];
2087 for oMap in oInstr.aoMaps:
2088 oMap.aoInstructions.append(oInstr);
2089
2090 #
2091 # Derive encoding from operands and maps.
2092 #
2093 if oInstr.sEncoding is None:
2094 if not oInstr.aoOperands:
2095 if oInstr.fUnused and oInstr.sSubOpcode:
2096 oInstr.sEncoding = 'VEX.ModR/M' if oInstr.onlyInVexMaps() else 'ModR/M';
2097 else:
2098 oInstr.sEncoding = 'VEX.fixed' if oInstr.onlyInVexMaps() else 'fixed';
2099 elif oInstr.aoOperands[0].usesModRM():
2100 if (len(oInstr.aoOperands) >= 2 and oInstr.aoOperands[1].sWhere == 'vvvv') \
2101 or oInstr.onlyInVexMaps():
2102 oInstr.sEncoding = 'VEX.ModR/M';
2103 else:
2104 oInstr.sEncoding = 'ModR/M';
2105
2106 #
2107 # Check the opstat value and add it to the opstat indexed dictionary.
2108 #
2109 if oInstr.sStats:
2110 if oInstr.sStats not in g_dAllInstructionsByStat:
2111 g_dAllInstructionsByStat[oInstr.sStats] = oInstr;
2112 else:
2113 self.error('Duplicate opstat value "%s"\nnew: %s\nold: %s'
2114 % (oInstr.sStats, oInstr, g_dAllInstructionsByStat[oInstr.sStats],));
2115
2116 #
2117 # Add to function indexed dictionary. We allow multiple instructions per function.
2118 #
2119 if oInstr.sFunction:
2120 if oInstr.sFunction not in g_dAllInstructionsByFunction:
2121 g_dAllInstructionsByFunction[oInstr.sFunction] = [oInstr,];
2122 else:
2123 g_dAllInstructionsByFunction[oInstr.sFunction].append(oInstr);
2124
2125 #self.debug('%d..%d: %s; %d @op tags' % (oInstr.iLineCreated, oInstr.iLineCompleted, oInstr.sFunction, oInstr.cOpTags));
2126 return True;
2127
2128 def doneInstructions(self, iLineInComment = None):
2129 """
2130 Done with current instruction.
2131 """
2132 for oInstr in self.aoCurInstrs:
2133 self.doneInstructionOne(oInstr, self.iLine if iLineInComment is None else self.iCommentLine + iLineInComment);
2134 if oInstr.fStub:
2135 self.cTotalStubs += 1;
2136
2137 self.cTotalInstr += len(self.aoCurInstrs);
2138
2139 self.sComment = '';
2140 self.aoCurInstrs = [];
2141 return True;
2142
2143 def setInstrunctionAttrib(self, sAttrib, oValue, fOverwrite = False):
2144 """
2145 Sets the sAttrib of all current instruction to oValue. If fOverwrite
2146 is False, only None values and empty strings are replaced.
2147 """
2148 for oInstr in self.aoCurInstrs:
2149 if fOverwrite is not True:
2150 oOldValue = getattr(oInstr, sAttrib);
2151 if oOldValue is not None:
2152 continue;
2153 setattr(oInstr, sAttrib, oValue);
2154
2155 def setInstrunctionArrayAttrib(self, sAttrib, iEntry, oValue, fOverwrite = False):
2156 """
2157 Sets the iEntry of the array sAttrib of all current instruction to oValue.
2158 If fOverwrite is False, only None values and empty strings are replaced.
2159 """
2160 for oInstr in self.aoCurInstrs:
2161 aoArray = getattr(oInstr, sAttrib);
2162 while len(aoArray) <= iEntry:
2163 aoArray.append(None);
2164 if fOverwrite is True or aoArray[iEntry] is None:
2165 aoArray[iEntry] = oValue;
2166
2167 def parseCommentOldOpcode(self, asLines):
2168 """ Deals with 'Opcode 0xff /4' like comments """
2169 asWords = asLines[0].split();
2170 if len(asWords) >= 2 \
2171 and asWords[0] == 'Opcode' \
2172 and ( asWords[1].startswith('0x')
2173 or asWords[1].startswith('0X')):
2174 asWords = asWords[:1];
2175 for iWord, sWord in enumerate(asWords):
2176 if sWord.startswith('0X'):
2177 sWord = '0x' + sWord[:2];
2178 asWords[iWord] = asWords;
2179 self.setInstrunctionAttrib('sRawOldOpcodes', ' '.join(asWords));
2180
2181 return False;
2182
2183 def ensureInstructionForOpTag(self, iTagLine):
2184 """ Ensure there is an instruction for the op-tag being parsed. """
2185 if not self.aoCurInstrs:
2186 self.addInstruction(self.iCommentLine + iTagLine);
2187 for oInstr in self.aoCurInstrs:
2188 oInstr.cOpTags += 1;
2189 if oInstr.cOpTags == 1:
2190 self.cTotalTagged += 1;
2191 return self.aoCurInstrs[-1];
2192
2193 @staticmethod
2194 def flattenSections(aasSections):
2195 """
2196 Flattens multiline sections into stripped single strings.
2197 Returns list of strings, on section per string.
2198 """
2199 asRet = [];
2200 for asLines in aasSections:
2201 if asLines:
2202 asRet.append(' '.join([sLine.strip() for sLine in asLines]));
2203 return asRet;
2204
2205 @staticmethod
2206 def flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = '\n'):
2207 """
2208 Flattens sections into a simple stripped string with newlines as
2209 section breaks. The final section does not sport a trailing newline.
2210 """
2211 # Typical: One section with a single line.
2212 if len(aasSections) == 1 and len(aasSections[0]) == 1:
2213 return aasSections[0][0].strip();
2214
2215 sRet = '';
2216 for iSection, asLines in enumerate(aasSections):
2217 if asLines:
2218 if iSection > 0:
2219 sRet += sSectionSep;
2220 sRet += sLineSep.join([sLine.strip() for sLine in asLines]);
2221 return sRet;
2222
2223
2224
2225 ## @name Tag parsers
2226 ## @{
2227
2228 def parseTagOpBrief(self, sTag, aasSections, iTagLine, iEndLine):
2229 """
2230 Tag: \@opbrief
2231 Value: Text description, multiple sections, appended.
2232
2233 Brief description. If not given, it's the first sentence from @opdesc.
2234 """
2235 oInstr = self.ensureInstructionForOpTag(iTagLine);
2236
2237 # Flatten and validate the value.
2238 sBrief = self.flattenAllSections(aasSections);
2239 if not sBrief:
2240 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
2241 if sBrief[-1] != '.':
2242 sBrief = sBrief + '.';
2243 if len(sBrief) > 180:
2244 return self.errorComment(iTagLine, '%s: value too long (max 180 chars): %s' % (sTag, sBrief));
2245 offDot = sBrief.find('.');
2246 while 0 <= offDot < len(sBrief) - 1 and sBrief[offDot + 1] != ' ':
2247 offDot = sBrief.find('.', offDot + 1);
2248 if offDot >= 0 and offDot != len(sBrief) - 1:
2249 return self.errorComment(iTagLine, '%s: only one sentence: %s' % (sTag, sBrief));
2250
2251 # Update the instruction.
2252 if oInstr.sBrief is not None:
2253 return self.errorComment(iTagLine, '%s: attempting to overwrite brief "%s" with "%s"'
2254 % (sTag, oInstr.sBrief, sBrief,));
2255 _ = iEndLine;
2256 return True;
2257
2258 def parseTagOpDesc(self, sTag, aasSections, iTagLine, iEndLine):
2259 """
2260 Tag: \@opdesc
2261 Value: Text description, multiple sections, appended.
2262
2263 It is used to describe instructions.
2264 """
2265 oInstr = self.ensureInstructionForOpTag(iTagLine);
2266 if aasSections:
2267 oInstr.asDescSections.extend(self.flattenSections(aasSections));
2268 return True;
2269
2270 _ = sTag; _ = iEndLine;
2271 return True;
2272
2273 def parseTagOpMnemonic(self, sTag, aasSections, iTagLine, iEndLine):
2274 """
2275 Tag: @opmenmonic
2276 Value: mnemonic
2277
2278 The 'mnemonic' value must be a valid C identifier string. Because of
2279 prefixes, groups and whatnot, there times when the mnemonic isn't that
2280 of an actual assembler mnemonic.
2281 """
2282 oInstr = self.ensureInstructionForOpTag(iTagLine);
2283
2284 # Flatten and validate the value.
2285 sMnemonic = self.flattenAllSections(aasSections);
2286 if not self.oReMnemonic.match(sMnemonic):
2287 return self.errorComment(iTagLine, '%s: invalid menmonic name: "%s"' % (sTag, sMnemonic,));
2288 if oInstr.sMnemonic is not None:
2289 return self.errorComment(iTagLine, '%s: attempting to overwrite menmonic "%s" with "%s"'
2290 % (sTag, oInstr.sMnemonic, sMnemonic,));
2291 oInstr.sMnemonic = sMnemonic
2292
2293 _ = iEndLine;
2294 return True;
2295
2296 def parseTagOpOperandN(self, sTag, aasSections, iTagLine, iEndLine):
2297 """
2298 Tags: \@op1, \@op2, \@op3, \@op4
2299 Value: [where:]type
2300
2301 The 'where' value indicates where the operand is found, like the 'reg'
2302 part of the ModR/M encoding. See Instruction.kdOperandLocations for
2303 a list.
2304
2305 The 'type' value indicates the operand type. These follow the types
2306 given in the opcode tables in the CPU reference manuals.
2307 See Instruction.kdOperandTypes for a list.
2308
2309 """
2310 oInstr = self.ensureInstructionForOpTag(iTagLine);
2311 idxOp = int(sTag[-1]) - 1;
2312 assert 0 <= idxOp < 4;
2313
2314 # flatten, split up, and validate the "where:type" value.
2315 sFlattened = self.flattenAllSections(aasSections);
2316 asSplit = sFlattened.split(':');
2317 if len(asSplit) == 1:
2318 sType = asSplit[0];
2319 sWhere = None;
2320 elif len(asSplit) == 2:
2321 (sWhere, sType) = asSplit;
2322 else:
2323 return self.errorComment(iTagLine, 'expected %s value on format "[<where>:]<type>" not "%s"' % (sTag, sFlattened,));
2324
2325 if sType not in g_kdOpTypes:
2326 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
2327 % (sTag, sType, ', '.join(g_kdOpTypes.keys()),));
2328 if sWhere is None:
2329 sWhere = g_kdOpTypes[sType][1];
2330 elif sWhere not in g_kdOpLocations:
2331 return self.errorComment(iTagLine, '%s: invalid where value "%s", valid: %s'
2332 % (sTag, sWhere, ', '.join(g_kdOpLocations.keys()),));
2333
2334 # Insert the operand, refusing to overwrite an existing one.
2335 while idxOp >= len(oInstr.aoOperands):
2336 oInstr.aoOperands.append(None);
2337 if oInstr.aoOperands[idxOp] is not None:
2338 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s:%s" with "%s:%s"'
2339 % ( sTag, oInstr.aoOperands[idxOp].sWhere, oInstr.aoOperands[idxOp].sType,
2340 sWhere, sType,));
2341 oInstr.aoOperands[idxOp] = Operand(sWhere, sType);
2342
2343 _ = iEndLine;
2344 return True;
2345
2346 def parseTagOpMaps(self, sTag, aasSections, iTagLine, iEndLine):
2347 """
2348 Tag: \@opmaps
2349 Value: map[,map2]
2350
2351 Indicates which maps the instruction is in. There is a default map
2352 associated with each input file.
2353 """
2354 oInstr = self.ensureInstructionForOpTag(iTagLine);
2355
2356 # Flatten, split up and validate the value.
2357 sFlattened = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',');
2358 asMaps = sFlattened.split(',');
2359 if not asMaps:
2360 return self.errorComment(iTagLine, '%s: value required' % (sTag,));
2361 for sMap in asMaps:
2362 if sMap not in g_dInstructionMaps:
2363 return self.errorComment(iTagLine, '%s: invalid map value: %s (valid values: %s)'
2364 % (sTag, sMap, ', '.join(g_dInstructionMaps.keys()),));
2365
2366 # Add the maps to the current list. Throw errors on duplicates.
2367 for oMap in oInstr.aoMaps:
2368 if oMap.sName in asMaps:
2369 return self.errorComment(iTagLine, '%s: duplicate map assignment: %s' % (sTag, oMap.sName));
2370
2371 for sMap in asMaps:
2372 oMap = g_dInstructionMaps[sMap];
2373 if oMap not in oInstr.aoMaps:
2374 oInstr.aoMaps.append(oMap);
2375 else:
2376 self.errorComment(iTagLine, '%s: duplicate map assignment (input): %s' % (sTag, sMap));
2377
2378 _ = iEndLine;
2379 return True;
2380
2381 def parseTagOpPfx(self, sTag, aasSections, iTagLine, iEndLine):
2382 """
2383 Tag: \@oppfx
2384 Value: n/a|none|0x66|0xf3|0xf2
2385
2386 Required prefix for the instruction. (In a (E)VEX context this is the
2387 value of the 'pp' field rather than an actual prefix.)
2388 """
2389 oInstr = self.ensureInstructionForOpTag(iTagLine);
2390
2391 # Flatten and validate the value.
2392 sFlattened = self.flattenAllSections(aasSections);
2393 asPrefixes = sFlattened.split();
2394 if len(asPrefixes) > 1:
2395 return self.errorComment(iTagLine, '%s: max one prefix: %s' % (sTag, asPrefixes,));
2396
2397 sPrefix = asPrefixes[0].lower();
2398 if sPrefix == 'none':
2399 sPrefix = 'none';
2400 elif sPrefix == 'n/a':
2401 sPrefix = None;
2402 else:
2403 if len(sPrefix) == 2:
2404 sPrefix = '0x' + sPrefix;
2405 if not _isValidOpcodeByte(sPrefix):
2406 return self.errorComment(iTagLine, '%s: invalid prefix: %s' % (sTag, sPrefix,));
2407
2408 if sPrefix is not None and sPrefix not in g_kdPrefixes:
2409 return self.errorComment(iTagLine, '%s: invalid prefix: %s (valid %s)' % (sTag, sPrefix, g_kdPrefixes,));
2410
2411 # Set it.
2412 if oInstr.sPrefix is not None:
2413 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sPrefix, sPrefix,));
2414 oInstr.sPrefix = sPrefix;
2415
2416 _ = iEndLine;
2417 return True;
2418
2419 def parseTagOpcode(self, sTag, aasSections, iTagLine, iEndLine):
2420 """
2421 Tag: \@opcode
2422 Value: 0x?? | /reg (TODO: | mr/reg | 11 /reg | !11 /reg | 11 mr/reg | !11 mr/reg)
2423
2424 The opcode byte or sub-byte for the instruction in the context of a map.
2425 """
2426 oInstr = self.ensureInstructionForOpTag(iTagLine);
2427
2428 # Flatten and validate the value.
2429 sOpcode = self.flattenAllSections(aasSections);
2430 if _isValidOpcodeByte(sOpcode):
2431 pass;
2432 elif len(sOpcode) == 2 and sOpcode.startswith('/') and sOpcode[-1] in '012345678':
2433 pass;
2434 elif len(sOpcode) == 4 and sOpcode.startswith('11/') and sOpcode[-1] in '012345678':
2435 pass;
2436 elif len(sOpcode) == 5 and sOpcode.startswith('!11/') and sOpcode[-1] in '012345678':
2437 pass;
2438 else:
2439 return self.errorComment(iTagLine, '%s: invalid opcode: %s' % (sTag, sOpcode,));
2440
2441 # Set it.
2442 if oInstr.sOpcode is not None:
2443 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sOpcode, sOpcode,));
2444 oInstr.sOpcode = sOpcode;
2445
2446 _ = iEndLine;
2447 return True;
2448
2449 def parseTagOpcodeSub(self, sTag, aasSections, iTagLine, iEndLine):
2450 """
2451 Tag: \@opcodesub
2452 Value: none | 11 mr/reg | !11 mr/reg | rex.w=0 | rex.w=1 | vex.l=0 | vex.l=1
2453 | 11 mr/reg vex.l=0 | 11 mr/reg vex.l=1 | !11 mr/reg vex.l=0 | !11 mr/reg vex.l=1
2454
2455 This is a simple way of dealing with encodings where the mod=3 and mod!=3
2456 represents exactly two different instructions. The more proper way would
2457 be to go via maps with two members, but this is faster.
2458 """
2459 oInstr = self.ensureInstructionForOpTag(iTagLine);
2460
2461 # Flatten and validate the value.
2462 sSubOpcode = self.flattenAllSections(aasSections);
2463 if sSubOpcode not in g_kdSubOpcodes:
2464 return self.errorComment(iTagLine, '%s: invalid sub opcode: %s (valid: 11, !11, none)' % (sTag, sSubOpcode,));
2465 sSubOpcode = g_kdSubOpcodes[sSubOpcode][0];
2466
2467 # Set it.
2468 if oInstr.sSubOpcode is not None:
2469 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
2470 % ( sTag, oInstr.sSubOpcode, sSubOpcode,));
2471 oInstr.sSubOpcode = sSubOpcode;
2472
2473 _ = iEndLine;
2474 return True;
2475
2476 def parseTagOpEnc(self, sTag, aasSections, iTagLine, iEndLine):
2477 """
2478 Tag: \@openc
2479 Value: ModR/M|fixed|prefix|<map name>
2480
2481 The instruction operand encoding style.
2482 """
2483 oInstr = self.ensureInstructionForOpTag(iTagLine);
2484
2485 # Flatten and validate the value.
2486 sEncoding = self.flattenAllSections(aasSections);
2487 if sEncoding in g_kdEncodings:
2488 pass;
2489 elif sEncoding in g_dInstructionMaps:
2490 pass;
2491 elif not _isValidOpcodeByte(sEncoding):
2492 return self.errorComment(iTagLine, '%s: invalid encoding: %s' % (sTag, sEncoding,));
2493
2494 # Set it.
2495 if oInstr.sEncoding is not None:
2496 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"'
2497 % ( sTag, oInstr.sEncoding, sEncoding,));
2498 oInstr.sEncoding = sEncoding;
2499
2500 _ = iEndLine;
2501 return True;
2502
2503 ## EFlags tag to Instruction attribute name.
2504 kdOpFlagToAttr = {
2505 '@opfltest': 'asFlTest',
2506 '@opflmodify': 'asFlModify',
2507 '@opflundef': 'asFlUndefined',
2508 '@opflset': 'asFlSet',
2509 '@opflclear': 'asFlClear',
2510 };
2511
2512 def parseTagOpEFlags(self, sTag, aasSections, iTagLine, iEndLine):
2513 """
2514 Tags: \@opfltest, \@opflmodify, \@opflundef, \@opflset, \@opflclear
2515 Value: <eflags specifier>
2516
2517 """
2518 oInstr = self.ensureInstructionForOpTag(iTagLine);
2519
2520 # Flatten, split up and validate the values.
2521 asFlags = self.flattenAllSections(aasSections, sLineSep = ',', sSectionSep = ',').split(',');
2522 if len(asFlags) == 1 and asFlags[0].lower() == 'none':
2523 asFlags = [];
2524 else:
2525 fRc = True;
2526 for iFlag, sFlag in enumerate(asFlags):
2527 if sFlag not in g_kdEFlagsMnemonics:
2528 if sFlag.strip() in g_kdEFlagsMnemonics:
2529 asFlags[iFlag] = sFlag.strip();
2530 else:
2531 fRc = self.errorComment(iTagLine, '%s: invalid EFLAGS value: %s' % (sTag, sFlag,));
2532 if not fRc:
2533 return False;
2534
2535 # Set them.
2536 asOld = getattr(oInstr, self.kdOpFlagToAttr[sTag]);
2537 if asOld is not None:
2538 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, asOld, asFlags,));
2539 setattr(oInstr, self.kdOpFlagToAttr[sTag], asFlags);
2540
2541 _ = iEndLine;
2542 return True;
2543
2544 def parseTagOpHints(self, sTag, aasSections, iTagLine, iEndLine):
2545 """
2546 Tag: \@ophints
2547 Value: Comma or space separated list of flags and hints.
2548
2549 This covers the disassembler flags table and more.
2550 """
2551 oInstr = self.ensureInstructionForOpTag(iTagLine);
2552
2553 # Flatten as a space separated list, split it up and validate the values.
2554 asHints = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
2555 if len(asHints) == 1 and asHints[0].lower() == 'none':
2556 asHints = [];
2557 else:
2558 fRc = True;
2559 for iHint, sHint in enumerate(asHints):
2560 if sHint not in g_kdHints:
2561 if sHint.strip() in g_kdHints:
2562 sHint[iHint] = sHint.strip();
2563 else:
2564 fRc = self.errorComment(iTagLine, '%s: invalid hint value: %s' % (sTag, sHint,));
2565 if not fRc:
2566 return False;
2567
2568 # Append them.
2569 for sHint in asHints:
2570 if sHint not in oInstr.dHints:
2571 oInstr.dHints[sHint] = True; # (dummy value, using dictionary for speed)
2572 else:
2573 self.errorComment(iTagLine, '%s: duplicate hint: %s' % ( sTag, sHint,));
2574
2575 _ = iEndLine;
2576 return True;
2577
2578 def parseTagOpDisEnum(self, sTag, aasSections, iTagLine, iEndLine):
2579 """
2580 Tag: \@opdisenum
2581 Value: OP_XXXX
2582
2583 This is for select a specific (legacy) disassembler enum value for the
2584 instruction.
2585 """
2586 oInstr = self.ensureInstructionForOpTag(iTagLine);
2587
2588 # Flatten and split.
2589 asWords = self.flattenAllSections(aasSections).split();
2590 if len(asWords) != 1:
2591 self.errorComment(iTagLine, '%s: expected exactly one value: %s' % (sTag, asWords,));
2592 if not asWords:
2593 return False;
2594 sDisEnum = asWords[0];
2595 if not self.oReDisEnum.match(sDisEnum):
2596 return self.errorComment(iTagLine, '%s: invalid disassembler OP_XXXX enum: %s (pattern: %s)'
2597 % (sTag, sDisEnum, self.oReDisEnum.pattern));
2598
2599 # Set it.
2600 if oInstr.sDisEnum is not None:
2601 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % (sTag, oInstr.sDisEnum, sDisEnum,));
2602 oInstr.sDisEnum = sDisEnum;
2603
2604 _ = iEndLine;
2605 return True;
2606
2607 def parseTagOpMinCpu(self, sTag, aasSections, iTagLine, iEndLine):
2608 """
2609 Tag: \@opmincpu
2610 Value: <simple CPU name>
2611
2612 Indicates when this instruction was introduced.
2613 """
2614 oInstr = self.ensureInstructionForOpTag(iTagLine);
2615
2616 # Flatten the value, split into words, make sure there's just one, valid it.
2617 asCpus = self.flattenAllSections(aasSections).split();
2618 if len(asCpus) > 1:
2619 self.errorComment(iTagLine, '%s: exactly one CPU name, please: %s' % (sTag, ' '.join(asCpus),));
2620
2621 sMinCpu = asCpus[0];
2622 if sMinCpu in g_kdCpuNames:
2623 oInstr.sMinCpu = sMinCpu;
2624 else:
2625 return self.errorComment(iTagLine, '%s: invalid CPU name: %s (names: %s)'
2626 % (sTag, sMinCpu, ','.join(sorted(g_kdCpuNames)),));
2627
2628 # Set it.
2629 if oInstr.sMinCpu is None:
2630 oInstr.sMinCpu = sMinCpu;
2631 elif oInstr.sMinCpu != sMinCpu:
2632 self.errorComment(iTagLine, '%s: attemting to overwrite "%s" with "%s"' % (sTag, oInstr.sMinCpu, sMinCpu,));
2633
2634 _ = iEndLine;
2635 return True;
2636
2637 def parseTagOpCpuId(self, sTag, aasSections, iTagLine, iEndLine):
2638 """
2639 Tag: \@opcpuid
2640 Value: none | <CPUID flag specifier>
2641
2642 CPUID feature bit which is required for the instruction to be present.
2643 """
2644 oInstr = self.ensureInstructionForOpTag(iTagLine);
2645
2646 # Flatten as a space separated list, split it up and validate the values.
2647 asCpuIds = self.flattenAllSections(aasSections, sLineSep = ' ', sSectionSep = ' ').replace(',', ' ').split();
2648 if len(asCpuIds) == 1 and asCpuIds[0].lower() == 'none':
2649 asCpuIds = [];
2650 else:
2651 fRc = True;
2652 for iCpuId, sCpuId in enumerate(asCpuIds):
2653 if sCpuId not in g_kdCpuIdFlags:
2654 if sCpuId.strip() in g_kdCpuIdFlags:
2655 sCpuId[iCpuId] = sCpuId.strip();
2656 else:
2657 fRc = self.errorComment(iTagLine, '%s: invalid CPUID value: %s' % (sTag, sCpuId,));
2658 if not fRc:
2659 return False;
2660
2661 # Append them.
2662 for sCpuId in asCpuIds:
2663 if sCpuId not in oInstr.asCpuIds:
2664 oInstr.asCpuIds.append(sCpuId);
2665 else:
2666 self.errorComment(iTagLine, '%s: duplicate CPUID: %s' % ( sTag, sCpuId,));
2667
2668 _ = iEndLine;
2669 return True;
2670
2671 def parseTagOpGroup(self, sTag, aasSections, iTagLine, iEndLine):
2672 """
2673 Tag: \@opgroup
2674 Value: op_grp1[_subgrp2[_subsubgrp3]]
2675
2676 Instruction grouping.
2677 """
2678 oInstr = self.ensureInstructionForOpTag(iTagLine);
2679
2680 # Flatten as a space separated list, split it up and validate the values.
2681 asGroups = self.flattenAllSections(aasSections).split();
2682 if len(asGroups) != 1:
2683 return self.errorComment(iTagLine, '%s: exactly one group, please: %s' % (sTag, asGroups,));
2684 sGroup = asGroups[0];
2685 if not self.oReGroupName.match(sGroup):
2686 return self.errorComment(iTagLine, '%s: invalid group name: %s (valid: %s)'
2687 % (sTag, sGroup, self.oReGroupName.pattern));
2688
2689 # Set it.
2690 if oInstr.sGroup is not None:
2691 return self.errorComment(iTagLine, '%s: attempting to overwrite "%s" with "%s"' % ( sTag, oInstr.sGroup, sGroup,));
2692 oInstr.sGroup = sGroup;
2693
2694 _ = iEndLine;
2695 return True;
2696
2697 def parseTagOpUnusedInvalid(self, sTag, aasSections, iTagLine, iEndLine):
2698 """
2699 Tag: \@opunused, \@opinvalid, \@opinvlstyle
2700 Value: <invalid opcode behaviour style>
2701
2702 The \@opunused indicates the specification is for a currently unused
2703 instruction encoding.
2704
2705 The \@opinvalid indicates the specification is for an invalid currently
2706 instruction encoding (like UD2).
2707
2708 The \@opinvlstyle just indicates how CPUs decode the instruction when
2709 not supported (\@opcpuid, \@opmincpu) or disabled.
2710 """
2711 oInstr = self.ensureInstructionForOpTag(iTagLine);
2712
2713 # Flatten as a space separated list, split it up and validate the values.
2714 asStyles = self.flattenAllSections(aasSections).split();
2715 if len(asStyles) != 1:
2716 return self.errorComment(iTagLine, '%s: exactly one invalid behviour style, please: %s' % (sTag, asStyles,));
2717 sStyle = asStyles[0];
2718 if sStyle not in g_kdInvalidStyles:
2719 return self.errorComment(iTagLine, '%s: invalid invalid behaviour style: %s (valid: %s)'
2720 % (sTag, sStyle, g_kdInvalidStyles.keys(),));
2721 # Set it.
2722 if oInstr.sInvalidStyle is not None:
2723 return self.errorComment(iTagLine,
2724 '%s: attempting to overwrite "%s" with "%s" (only one @opunused, @opinvalid, @opinvlstyle)'
2725 % ( sTag, oInstr.sInvalidStyle, sStyle,));
2726 oInstr.sInvalidStyle = sStyle;
2727 if sTag == '@opunused':
2728 oInstr.fUnused = True;
2729 elif sTag == '@opinvalid':
2730 oInstr.fInvalid = True;
2731
2732 _ = iEndLine;
2733 return True;
2734
2735 def parseTagOpTest(self, sTag, aasSections, iTagLine, iEndLine): # pylint: disable=too-many-locals
2736 """
2737 Tag: \@optest
2738 Value: [<selectors>[ ]?] <inputs> -> <outputs>
2739 Example: mode==64bit / in1=0xfffffffe:dw in2=1:dw -> out1=0xffffffff:dw outfl=a?,p?
2740
2741 The main idea here is to generate basic instruction tests.
2742
2743 The probably simplest way of handling the diverse input, would be to use
2744 it to produce size optimized byte code for a simple interpreter that
2745 modifies the register input and output states.
2746
2747 An alternative to the interpreter would be creating multiple tables,
2748 but that becomes rather complicated wrt what goes where and then to use
2749 them in an efficient manner.
2750 """
2751 oInstr = self.ensureInstructionForOpTag(iTagLine);
2752
2753 #
2754 # Do it section by section.
2755 #
2756 for asSectionLines in aasSections:
2757 #
2758 # Sort the input into outputs, inputs and selector conditions.
2759 #
2760 sFlatSection = self.flattenAllSections([asSectionLines,]);
2761 if not sFlatSection:
2762 self.errorComment(iTagLine, '%s: missing value (dbg: aasSections=%s)' % ( sTag, aasSections));
2763 continue;
2764 oTest = InstructionTest(oInstr);
2765
2766 asSelectors = [];
2767 asInputs = [];
2768 asOutputs = [];
2769 asCur = asOutputs;
2770 fRc = True;
2771 asWords = sFlatSection.split();
2772 for iWord in range(len(asWords) - 1, -1, -1):
2773 sWord = asWords[iWord];
2774 # Check for array switchers.
2775 if sWord == '->':
2776 if asCur != asOutputs:
2777 fRc = self.errorComment(iTagLine, '%s: "->" shall only occure once: %s' % (sTag, sFlatSection,));
2778 break;
2779 asCur = asInputs;
2780 elif sWord == '/':
2781 if asCur != asInputs:
2782 fRc = self.errorComment(iTagLine, '%s: "/" shall only occure once: %s' % (sTag, sFlatSection,));
2783 break;
2784 asCur = asSelectors;
2785 else:
2786 asCur.insert(0, sWord);
2787
2788 #
2789 # Validate and add selectors.
2790 #
2791 for sCond in asSelectors:
2792 sCondExp = TestSelector.kdPredicates.get(sCond, sCond);
2793 oSelector = None;
2794 for sOp in TestSelector.kasCompareOps:
2795 off = sCondExp.find(sOp);
2796 if off >= 0:
2797 sVariable = sCondExp[:off];
2798 sValue = sCondExp[off + len(sOp):];
2799 if sVariable in TestSelector.kdVariables:
2800 if sValue in TestSelector.kdVariables[sVariable]:
2801 oSelector = TestSelector(sVariable, sOp, sValue);
2802 else:
2803 self.errorComment(iTagLine, '%s: invalid condition value "%s" in "%s" (valid: %s)'
2804 % ( sTag, sValue, sCond,
2805 TestSelector.kdVariables[sVariable].keys(),));
2806 else:
2807 self.errorComment(iTagLine, '%s: invalid condition variable "%s" in "%s" (valid: %s)'
2808 % ( sTag, sVariable, sCond, TestSelector.kdVariables.keys(),));
2809 break;
2810 if oSelector is not None:
2811 for oExisting in oTest.aoSelectors:
2812 if oExisting.sVariable == oSelector.sVariable:
2813 self.errorComment(iTagLine, '%s: already have a selector for variable "%s" (existing: %s, new: %s)'
2814 % ( sTag, oSelector.sVariable, oExisting, oSelector,));
2815 oTest.aoSelectors.append(oSelector);
2816 else:
2817 fRc = self.errorComment(iTagLine, '%s: failed to parse selector: %s' % ( sTag, sCond,));
2818
2819 #
2820 # Validate outputs and inputs, adding them to the test as we go along.
2821 #
2822 for asItems, sDesc, aoDst in [ (asInputs, 'input', oTest.aoInputs), (asOutputs, 'output', oTest.aoOutputs)]:
2823 asValidFieldKinds = [ 'both', sDesc, ];
2824 for sItem in asItems:
2825 oItem = None;
2826 for sOp in TestInOut.kasOperators:
2827 off = sItem.find(sOp);
2828 if off < 0:
2829 continue;
2830 sField = sItem[:off];
2831 sValueType = sItem[off + len(sOp):];
2832 if sField in TestInOut.kdFields \
2833 and TestInOut.kdFields[sField][1] in asValidFieldKinds:
2834 asSplit = sValueType.split(':', 1);
2835 sValue = asSplit[0];
2836 sType = asSplit[1] if len(asSplit) > 1 else TestInOut.kdFields[sField][0];
2837 if sType in TestInOut.kdTypes:
2838 oValid = TestInOut.kdTypes[sType].validate(sValue);
2839 if oValid is True:
2840 if not TestInOut.kdTypes[sType].isAndOrPair(sValue) or sOp == '&|=':
2841 oItem = TestInOut(sField, sOp, sValue, sType);
2842 else:
2843 self.errorComment(iTagLine, '%s: and-or %s value "%s" can only be used with "&|="'
2844 % ( sTag, sDesc, sItem, ));
2845 else:
2846 self.errorComment(iTagLine, '%s: invalid %s value "%s" in "%s" (type: %s): %s'
2847 % ( sTag, sDesc, sValue, sItem, sType, oValid, ));
2848 else:
2849 self.errorComment(iTagLine, '%s: invalid %s type "%s" in "%s" (valid types: %s)'
2850 % ( sTag, sDesc, sType, sItem, TestInOut.kdTypes.keys(),));
2851 else:
2852 self.errorComment(iTagLine, '%s: invalid %s field "%s" in "%s"\nvalid fields: %s'
2853 % ( sTag, sDesc, sField, sItem,
2854 ', '.join([sKey for sKey, asVal in TestInOut.kdFields.items()
2855 if asVal[1] in asValidFieldKinds]),));
2856 break;
2857 if oItem is not None:
2858 for oExisting in aoDst:
2859 if oExisting.sField == oItem.sField and oExisting.sOp == oItem.sOp:
2860 self.errorComment(iTagLine,
2861 '%s: already have a "%s" assignment for field "%s" (existing: %s, new: %s)'
2862 % ( sTag, oItem.sOp, oItem.sField, oExisting, oItem,));
2863 aoDst.append(oItem);
2864 else:
2865 fRc = self.errorComment(iTagLine, '%s: failed to parse assignment: %s' % ( sTag, sItem,));
2866
2867 #
2868 # .
2869 #
2870 if fRc:
2871 oInstr.aoTests.append(oTest);
2872 else:
2873 self.errorComment(iTagLine, '%s: failed to parse test: %s' % (sTag, ' '.join(asWords),));
2874 self.errorComment(iTagLine, '%s: asSelectors=%s / asInputs=%s -> asOutputs=%s'
2875 % (sTag, asSelectors, asInputs, asOutputs,));
2876
2877 _ = iEndLine;
2878 return True;
2879
2880 def parseTagOpTestNum(self, sTag, aasSections, iTagLine, iEndLine):
2881 """
2882 Numbered \@optest tag. Either \@optest42 or \@optest[42].
2883 """
2884 oInstr = self.ensureInstructionForOpTag(iTagLine);
2885
2886 iTest = 0;
2887 if sTag[-1] == ']':
2888 iTest = int(sTag[8:-1]);
2889 else:
2890 iTest = int(sTag[7:]);
2891
2892 if iTest != len(oInstr.aoTests):
2893 self.errorComment(iTagLine, '%s: incorrect test number: %u, actual %u' % (sTag, iTest, len(oInstr.aoTests),));
2894 return self.parseTagOpTest(sTag, aasSections, iTagLine, iEndLine);
2895
2896 def parseTagOpTestIgnore(self, sTag, aasSections, iTagLine, iEndLine):
2897 """
2898 Tag: \@optestign | \@optestignore
2899 Value: <value is ignored>
2900
2901 This is a simple trick to ignore a test while debugging another.
2902
2903 See also \@oponlytest.
2904 """
2905 _ = sTag; _ = aasSections; _ = iTagLine; _ = iEndLine;
2906 return True;
2907
2908 def parseTagOpCopyTests(self, sTag, aasSections, iTagLine, iEndLine):
2909 """
2910 Tag: \@opcopytests
2911 Value: <opstat | function> [..]
2912 Example: \@opcopytests add_Eb_Gb
2913
2914 Trick to avoid duplicating tests for different encodings of the same
2915 operation.
2916 """
2917 oInstr = self.ensureInstructionForOpTag(iTagLine);
2918
2919 # Flatten, validate and append the copy job to the instruction. We execute
2920 # them after parsing all the input so we can handle forward references.
2921 asToCopy = self.flattenAllSections(aasSections).split();
2922 if not asToCopy:
2923 return self.errorComment(iTagLine, '%s: requires at least on reference value' % (sTag,));
2924 for sToCopy in asToCopy:
2925 if sToCopy not in oInstr.asCopyTests:
2926 if self.oReStatsName.match(sToCopy) or self.oReFunctionName.match(sToCopy):
2927 oInstr.asCopyTests.append(sToCopy);
2928 else:
2929 self.errorComment(iTagLine, '%s: invalid instruction reference (opstat or function) "%s" (valid: %s or %s)'
2930 % (sTag, sToCopy, self.oReStatsName.pattern, self.oReFunctionName.pattern));
2931 else:
2932 self.errorComment(iTagLine, '%s: ignoring duplicate "%s"' % (sTag, sToCopy,));
2933
2934 _ = iEndLine;
2935 return True;
2936
2937 def parseTagOpOnlyTest(self, sTag, aasSections, iTagLine, iEndLine):
2938 """
2939 Tag: \@oponlytest | \@oponly
2940 Value: none
2941
2942 Only test instructions with this tag. This is a trick that is handy
2943 for singling out one or two new instructions or tests.
2944
2945 See also \@optestignore.
2946 """
2947 oInstr = self.ensureInstructionForOpTag(iTagLine);
2948
2949 # Validate and add instruction to only test dictionary.
2950 sValue = self.flattenAllSections(aasSections).strip();
2951 if sValue:
2952 return self.errorComment(iTagLine, '%s: does not take any value: %s' % (sTag, sValue));
2953
2954 if oInstr not in g_aoOnlyTestInstructions:
2955 g_aoOnlyTestInstructions.append(oInstr);
2956
2957 _ = iEndLine;
2958 return True;
2959
2960 def parseTagOpXcptType(self, sTag, aasSections, iTagLine, iEndLine):
2961 """
2962 Tag: \@opxcpttype
2963 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]
2964
2965 Sets the SSE or AVX exception type (see SDMv2 2.4, 2.7).
2966 """
2967 oInstr = self.ensureInstructionForOpTag(iTagLine);
2968
2969 # Flatten as a space separated list, split it up and validate the values.
2970 asTypes = self.flattenAllSections(aasSections).split();
2971 if len(asTypes) != 1:
2972 return self.errorComment(iTagLine, '%s: exactly one invalid exception type, please: %s' % (sTag, asTypes,));
2973 sType = asTypes[0];
2974 if sType not in g_kdXcptTypes:
2975 return self.errorComment(iTagLine, '%s: invalid invalid exception type: %s (valid: %s)'
2976 % (sTag, sType, sorted(g_kdXcptTypes.keys()),));
2977 # Set it.
2978 if oInstr.sXcptType is not None:
2979 return self.errorComment(iTagLine,
2980 '%s: attempting to overwrite "%s" with "%s" (only one @opxcpttype)'
2981 % ( sTag, oInstr.sXcptType, sType,));
2982 oInstr.sXcptType = sType;
2983
2984 _ = iEndLine;
2985 return True;
2986
2987 def parseTagOpFunction(self, sTag, aasSections, iTagLine, iEndLine):
2988 """
2989 Tag: \@opfunction
2990 Value: <VMM function name>
2991
2992 This is for explicitly setting the IEM function name. Normally we pick
2993 this up from the FNIEMOP_XXX macro invocation after the description, or
2994 generate it from the mnemonic and operands.
2995
2996 It it thought it maybe necessary to set it when specifying instructions
2997 which implementation isn't following immediately or aren't implemented yet.
2998 """
2999 oInstr = self.ensureInstructionForOpTag(iTagLine);
3000
3001 # Flatten and validate the value.
3002 sFunction = self.flattenAllSections(aasSections);
3003 if not self.oReFunctionName.match(sFunction):
3004 return self.errorComment(iTagLine, '%s: invalid VMM function name: "%s" (valid: %s)'
3005 % (sTag, sFunction, self.oReFunctionName.pattern));
3006
3007 if oInstr.sFunction is not None:
3008 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM function name "%s" with "%s"'
3009 % (sTag, oInstr.sFunction, sFunction,));
3010 oInstr.sFunction = sFunction;
3011
3012 _ = iEndLine;
3013 return True;
3014
3015 def parseTagOpStats(self, sTag, aasSections, iTagLine, iEndLine):
3016 """
3017 Tag: \@opstats
3018 Value: <VMM statistics base name>
3019
3020 This is for explicitly setting the statistics name. Normally we pick
3021 this up from the IEMOP_MNEMONIC macro invocation, or generate it from
3022 the mnemonic and operands.
3023
3024 It it thought it maybe necessary to set it when specifying instructions
3025 which implementation isn't following immediately or aren't implemented yet.
3026 """
3027 oInstr = self.ensureInstructionForOpTag(iTagLine);
3028
3029 # Flatten and validate the value.
3030 sStats = self.flattenAllSections(aasSections);
3031 if not self.oReStatsName.match(sStats):
3032 return self.errorComment(iTagLine, '%s: invalid VMM statistics name: "%s" (valid: %s)'
3033 % (sTag, sStats, self.oReStatsName.pattern));
3034
3035 if oInstr.sStats is not None:
3036 return self.errorComment(iTagLine, '%s: attempting to overwrite VMM statistics base name "%s" with "%s"'
3037 % (sTag, oInstr.sStats, sStats,));
3038 oInstr.sStats = sStats;
3039
3040 _ = iEndLine;
3041 return True;
3042
3043 def parseTagOpDone(self, sTag, aasSections, iTagLine, iEndLine):
3044 """
3045 Tag: \@opdone
3046 Value: none
3047
3048 Used to explictily flush the instructions that have been specified.
3049 """
3050 sFlattened = self.flattenAllSections(aasSections);
3051 if sFlattened != '':
3052 return self.errorComment(iTagLine, '%s: takes no value, found: "%s"' % (sTag, sFlattened,));
3053 _ = sTag; _ = iEndLine;
3054 return self.doneInstructions();
3055
3056 ## @}
3057
3058
3059 def parseComment(self):
3060 """
3061 Parse the current comment (self.sComment).
3062
3063 If it's a opcode specifiying comment, we reset the macro stuff.
3064 """
3065 #
3066 # Reject if comment doesn't seem to contain anything interesting.
3067 #
3068 if self.sComment.find('Opcode') < 0 \
3069 and self.sComment.find('@') < 0:
3070 return False;
3071
3072 #
3073 # Split the comment into lines, removing leading asterisks and spaces.
3074 # Also remove leading and trailing empty lines.
3075 #
3076 asLines = self.sComment.split('\n');
3077 for iLine, sLine in enumerate(asLines):
3078 asLines[iLine] = sLine.lstrip().lstrip('*').lstrip();
3079
3080 while asLines and not asLines[0]:
3081 self.iCommentLine += 1;
3082 asLines.pop(0);
3083
3084 while asLines and not asLines[-1]:
3085 asLines.pop(len(asLines) - 1);
3086
3087 #
3088 # Check for old style: Opcode 0x0f 0x12
3089 #
3090 if asLines[0].startswith('Opcode '):
3091 self.parseCommentOldOpcode(asLines);
3092
3093 #
3094 # Look for @op* tagged data.
3095 #
3096 cOpTags = 0;
3097 sFlatDefault = None;
3098 sCurTag = '@default';
3099 iCurTagLine = 0;
3100 asCurSection = [];
3101 aasSections = [ asCurSection, ];
3102 for iLine, sLine in enumerate(asLines):
3103 if not sLine.startswith('@'):
3104 if sLine:
3105 asCurSection.append(sLine);
3106 elif asCurSection:
3107 asCurSection = [];
3108 aasSections.append(asCurSection);
3109 else:
3110 #
3111 # Process the previous tag.
3112 #
3113 if not asCurSection and len(aasSections) > 1:
3114 aasSections.pop(-1);
3115 if sCurTag in self.dTagHandlers:
3116 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
3117 cOpTags += 1;
3118 elif sCurTag.startswith('@op'):
3119 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
3120 elif sCurTag == '@default':
3121 sFlatDefault = self.flattenAllSections(aasSections);
3122 elif '@op' + sCurTag[1:] in self.dTagHandlers:
3123 self.errorComment(iCurTagLine, 'Did you mean "@op%s" rather than "%s"?' % (sCurTag[1:], sCurTag));
3124 elif sCurTag in ['@encoding', '@opencoding']:
3125 self.errorComment(iCurTagLine, 'Did you mean "@openc" rather than "%s"?' % (sCurTag,));
3126
3127 #
3128 # New tag.
3129 #
3130 asSplit = sLine.split(None, 1);
3131 sCurTag = asSplit[0].lower();
3132 if len(asSplit) > 1:
3133 asCurSection = [asSplit[1],];
3134 else:
3135 asCurSection = [];
3136 aasSections = [asCurSection, ];
3137 iCurTagLine = iLine;
3138
3139 #
3140 # Process the final tag.
3141 #
3142 if not asCurSection and len(aasSections) > 1:
3143 aasSections.pop(-1);
3144 if sCurTag in self.dTagHandlers:
3145 self.dTagHandlers[sCurTag](sCurTag, aasSections, iCurTagLine, iLine);
3146 cOpTags += 1;
3147 elif sCurTag.startswith('@op'):
3148 self.errorComment(iCurTagLine, 'Unknown tag: %s' % (sCurTag));
3149 elif sCurTag == '@default':
3150 sFlatDefault = self.flattenAllSections(aasSections);
3151
3152 #
3153 # Don't allow default text in blocks containing @op*.
3154 #
3155 if cOpTags > 0 and sFlatDefault:
3156 self.errorComment(0, 'Untagged comment text is not allowed with @op*: %s' % (sFlatDefault,));
3157
3158 return True;
3159
3160 def parseMacroInvocation(self, sInvocation):
3161 """
3162 Parses a macro invocation.
3163
3164 Returns a tuple, first element is the offset following the macro
3165 invocation. The second element is a list of macro arguments, where the
3166 zero'th is the macro name.
3167 """
3168 # First the name.
3169 offOpen = sInvocation.find('(');
3170 if offOpen <= 0:
3171 self.raiseError("macro invocation open parenthesis not found");
3172 sName = sInvocation[:offOpen].strip();
3173 if not self.oReMacroName.match(sName):
3174 return self.error("invalid macro name '%s'" % (sName,));
3175 asRet = [sName, ];
3176
3177 # Arguments.
3178 iLine = self.iLine;
3179 cDepth = 1;
3180 off = offOpen + 1;
3181 offStart = off;
3182 chQuote = None;
3183 while cDepth > 0:
3184 if off >= len(sInvocation):
3185 if iLine >= len(self.asLines):
3186 self.error('macro invocation beyond end of file');
3187 return (off, asRet);
3188 sInvocation += self.asLines[iLine];
3189 iLine += 1;
3190 ch = sInvocation[off];
3191
3192 if chQuote:
3193 if ch == '\\' and off + 1 < len(sInvocation):
3194 off += 1;
3195 elif ch == chQuote:
3196 chQuote = None;
3197 elif ch in ('"', '\'',):
3198 chQuote = ch;
3199 elif ch in (',', ')',):
3200 if cDepth == 1:
3201 asRet.append(sInvocation[offStart:off].strip());
3202 offStart = off + 1;
3203 if ch == ')':
3204 cDepth -= 1;
3205 elif ch == '(':
3206 cDepth += 1;
3207 off += 1;
3208
3209 return (off, asRet);
3210
3211 def findAndParseMacroInvocationEx(self, sCode, sMacro):
3212 """
3213 Returns (len(sCode), None) if not found, parseMacroInvocation result if found.
3214 """
3215 offHit = sCode.find(sMacro);
3216 if offHit >= 0 and sCode[offHit + len(sMacro):].strip()[0] == '(':
3217 offAfter, asRet = self.parseMacroInvocation(sCode[offHit:])
3218 return (offHit + offAfter, asRet);
3219 return (len(sCode), None);
3220
3221 def findAndParseMacroInvocation(self, sCode, sMacro):
3222 """
3223 Returns None if not found, arguments as per parseMacroInvocation if found.
3224 """
3225 return self.findAndParseMacroInvocationEx(sCode, sMacro)[1];
3226
3227 def findAndParseFirstMacroInvocation(self, sCode, asMacro):
3228 """
3229 Returns same as findAndParseMacroInvocation.
3230 """
3231 for sMacro in asMacro:
3232 asRet = self.findAndParseMacroInvocation(sCode, sMacro);
3233 if asRet is not None:
3234 return asRet;
3235 return None;
3236
3237 def workerIemOpMnemonicEx(self, sMacro, sStats, sAsm, sForm, sUpper, sLower, # pylint: disable=too-many-arguments
3238 sDisHints, sIemHints, asOperands):
3239 """
3240 Processes one of the a IEMOP_MNEMONIC0EX, IEMOP_MNEMONIC1EX, IEMOP_MNEMONIC2EX,
3241 IEMOP_MNEMONIC3EX, and IEMOP_MNEMONIC4EX macros.
3242 """
3243 #
3244 # Some invocation checks.
3245 #
3246 if sUpper != sUpper.upper():
3247 self.error('%s: bad a_Upper parameter: %s' % (sMacro, sUpper,));
3248 if sLower != sLower.lower():
3249 self.error('%s: bad a_Lower parameter: %s' % (sMacro, sLower,));
3250 if sUpper.lower() != sLower:
3251 self.error('%s: a_Upper and a_Lower parameters does not match: %s vs %s' % (sMacro, sUpper, sLower,));
3252 if not self.oReMnemonic.match(sLower):
3253 self.error('%s: invalid a_Lower: %s (valid: %s)' % (sMacro, sLower, self.oReMnemonic.pattern,));
3254
3255 #
3256 # Check if sIemHints tells us to not consider this macro invocation.
3257 #
3258 if sIemHints.find('IEMOPHINT_SKIP_PYTHON') >= 0:
3259 return True;
3260
3261 # Apply to the last instruction only for now.
3262 if not self.aoCurInstrs:
3263 self.addInstruction();
3264 oInstr = self.aoCurInstrs[-1];
3265 if oInstr.iLineMnemonicMacro == -1:
3266 oInstr.iLineMnemonicMacro = self.iLine;
3267 else:
3268 self.error('%s: already saw a IEMOP_MNEMONIC* macro on line %u for this instruction'
3269 % (sMacro, oInstr.iLineMnemonicMacro,));
3270
3271 # Mnemonic
3272 if oInstr.sMnemonic is None:
3273 oInstr.sMnemonic = sLower;
3274 elif oInstr.sMnemonic != sLower:
3275 self.error('%s: current instruction and a_Lower does not match: %s vs %s' % (sMacro, oInstr.sMnemonic, sLower,));
3276
3277 # Process operands.
3278 if len(oInstr.aoOperands) not in [0, len(asOperands)]:
3279 self.error('%s: number of operands given by @opN does not match macro: %s vs %s'
3280 % (sMacro, len(oInstr.aoOperands), len(asOperands),));
3281 for iOperand, sType in enumerate(asOperands):
3282 sWhere = g_kdOpTypes.get(sType, [None, None])[1];
3283 if sWhere is None:
3284 self.error('%s: unknown a_Op%u value: %s' % (sMacro, iOperand + 1, sType));
3285 if iOperand < len(oInstr.aoOperands): # error recovery.
3286 sWhere = oInstr.aoOperands[iOperand].sWhere;
3287 sType = oInstr.aoOperands[iOperand].sType;
3288 else:
3289 sWhere = 'reg';
3290 sType = 'Gb';
3291 if iOperand == len(oInstr.aoOperands):
3292 oInstr.aoOperands.append(Operand(sWhere, sType))
3293 elif oInstr.aoOperands[iOperand].sWhere != sWhere or oInstr.aoOperands[iOperand].sType != sType:
3294 self.error('%s: @op%u and a_Op%u mismatch: %s:%s vs %s:%s'
3295 % (sMacro, iOperand + 1, iOperand + 1, oInstr.aoOperands[iOperand].sWhere,
3296 oInstr.aoOperands[iOperand].sType, sWhere, sType,));
3297
3298 # Encoding.
3299 if sForm not in g_kdIemForms:
3300 self.error('%s: unknown a_Form value: %s' % (sMacro, sForm,));
3301 else:
3302 if oInstr.sEncoding is None:
3303 oInstr.sEncoding = g_kdIemForms[sForm][0];
3304 elif g_kdIemForms[sForm][0] != oInstr.sEncoding:
3305 self.error('%s: current instruction @openc and a_Form does not match: %s vs %s (%s)'
3306 % (sMacro, oInstr.sEncoding, g_kdIemForms[sForm], sForm));
3307
3308 # Check the parameter locations for the encoding.
3309 if g_kdIemForms[sForm][1] is not None:
3310 if len(g_kdIemForms[sForm][1]) > len(oInstr.aoOperands):
3311 self.error('%s: The a_Form=%s has a different operand count: %s (form) vs %s'
3312 % (sMacro, sForm, len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands) ));
3313 else:
3314 for iOperand, sWhere in enumerate(g_kdIemForms[sForm][1]):
3315 if oInstr.aoOperands[iOperand].sWhere != sWhere:
3316 self.error('%s: current instruction @op%u and a_Form location does not match: %s vs %s (%s)'
3317 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sWhere, sWhere, sForm,));
3318 sOpFormMatch = g_kdOpTypes[oInstr.aoOperands[iOperand].sType][4];
3319 if (sOpFormMatch in [ 'REG', 'MEM', ] and sForm.find('_' + sOpFormMatch) < 0) \
3320 or (sOpFormMatch in [ 'FIXED', ] and sForm.find(sOpFormMatch) < 0) \
3321 or (sOpFormMatch == 'RM' and (sForm.find('_MEM') > 0 or sForm.find('_REG') > 0) ) \
3322 or (sOpFormMatch == 'V' and ( not (sForm.find('VEX') > 0 or sForm.find('XOP')) \
3323 or sForm.replace('VEX','').find('V') < 0) ):
3324 self.error('%s: current instruction @op%u and a_Form type does not match: %s/%s vs %s'
3325 % (sMacro, iOperand + 1, oInstr.aoOperands[iOperand].sType, sOpFormMatch, sForm, ));
3326 if len(g_kdIemForms[sForm][1]) < len(oInstr.aoOperands):
3327 for iOperand in range(len(g_kdIemForms[sForm][1]), len(oInstr.aoOperands)):
3328 if oInstr.aoOperands[iOperand].sType != 'FIXED' \
3329 and g_kdOpTypes[oInstr.aoOperands[iOperand].sType][0] != 'IDX_ParseFixedReg':
3330 self.error('%s: Expected FIXED type operand #%u following operands given by a_Form=%s: %s (%s)'
3331 % (sMacro, iOperand, sForm, oInstr.aoOperands[iOperand].sType,
3332 oInstr.aoOperands[iOperand].sWhere));
3333
3334
3335 # Check @opcodesub
3336 if oInstr.sSubOpcode \
3337 and g_kdIemForms[sForm][2] \
3338 and oInstr.sSubOpcode.find(g_kdIemForms[sForm][2]) < 0:
3339 self.error('%s: current instruction @opcodesub and a_Form does not match: %s vs %s (%s)'
3340 % (sMacro, oInstr.sSubOpcode, g_kdIemForms[sForm][2], sForm,));
3341
3342 # Stats.
3343 if not self.oReStatsName.match(sStats):
3344 self.error('%s: invalid a_Stats value: %s' % (sMacro, sStats,));
3345 elif oInstr.sStats is None:
3346 oInstr.sStats = sStats;
3347 elif oInstr.sStats != sStats:
3348 self.error('%s: mismatching @opstats and a_Stats value: %s vs %s'
3349 % (sMacro, oInstr.sStats, sStats,));
3350
3351 # Process the hints (simply merge with @ophints w/o checking anything).
3352 for sHint in sDisHints.split('|'):
3353 sHint = sHint.strip();
3354 if sHint.startswith('DISOPTYPE_'):
3355 sShortHint = sHint[len('DISOPTYPE_'):].lower();
3356 if sShortHint in g_kdHints:
3357 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
3358 else:
3359 self.error('%s: unknown a_fDisHints value: %s' % (sMacro, sHint,));
3360 elif sHint != '0':
3361 self.error('%s: expected a_fDisHints value: %s' % (sMacro, sHint,));
3362
3363 for sHint in sIemHints.split('|'):
3364 sHint = sHint.strip();
3365 if sHint.startswith('IEMOPHINT_'):
3366 sShortHint = sHint[len('IEMOPHINT_'):].lower();
3367 if sShortHint in g_kdHints:
3368 oInstr.dHints[sShortHint] = True; # (dummy value, using dictionary for speed)
3369 else:
3370 self.error('%s: unknown a_fIemHints value: %s' % (sMacro, sHint,));
3371 elif sHint != '0':
3372 self.error('%s: expected a_fIemHints value: %s' % (sMacro, sHint,));
3373
3374 _ = sAsm;
3375 return True;
3376
3377 def workerIemOpMnemonic(self, sMacro, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands):
3378 """
3379 Processes one of the a IEMOP_MNEMONIC0, IEMOP_MNEMONIC1, IEMOP_MNEMONIC2,
3380 IEMOP_MNEMONIC3, and IEMOP_MNEMONIC4 macros.
3381 """
3382 if not asOperands:
3383 return self.workerIemOpMnemonicEx(sMacro, sLower, sLower, sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
3384 return self.workerIemOpMnemonicEx(sMacro, sLower + '_' + '_'.join(asOperands), sLower + ' ' + ','.join(asOperands),
3385 sForm, sUpper, sLower, sDisHints, sIemHints, asOperands);
3386
3387 def checkCodeForMacro(self, sCode):
3388 """
3389 Checks code for relevant macro invocation.
3390 """
3391 #
3392 # Scan macro invocations.
3393 #
3394 if sCode.find('(') > 0:
3395 # Look for instruction decoder function definitions. ASSUME single line.
3396 asArgs = self.findAndParseFirstMacroInvocation(sCode,
3397 [ 'FNIEMOP_DEF',
3398 'FNIEMOP_STUB',
3399 'FNIEMOP_STUB_1',
3400 'FNIEMOP_UD_STUB',
3401 'FNIEMOP_UD_STUB_1' ]);
3402 if asArgs is not None:
3403 sFunction = asArgs[1];
3404
3405 if not self.aoCurInstrs:
3406 self.addInstruction();
3407 for oInstr in self.aoCurInstrs:
3408 if oInstr.iLineFnIemOpMacro == -1:
3409 oInstr.iLineFnIemOpMacro = self.iLine;
3410 else:
3411 self.error('%s: already seen a FNIEMOP_XXX macro for %s' % (asArgs[0], oInstr,) );
3412 self.setInstrunctionAttrib('sFunction', sFunction);
3413 self.setInstrunctionAttrib('fStub', asArgs[0].find('STUB') > 0, fOverwrite = True);
3414 self.setInstrunctionAttrib('fUdStub', asArgs[0].find('UD_STUB') > 0, fOverwrite = True);
3415 if asArgs[0].find('STUB') > 0:
3416 self.doneInstructions();
3417 return True;
3418
3419 # IEMOP_HLP_DONE_VEX_DECODING_*
3420 asArgs = self.findAndParseFirstMacroInvocation(sCode,
3421 [ 'IEMOP_HLP_DONE_VEX_DECODING',
3422 'IEMOP_HLP_DONE_VEX_DECODING_L0',
3423 'IEMOP_HLP_DONE_VEX_DECODING_NO_VVVV',
3424 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV',
3425 ]);
3426 if asArgs is not None:
3427 sMacro = asArgs[0];
3428 if sMacro in ('IEMOP_HLP_DONE_VEX_DECODING_L0', 'IEMOP_HLP_DONE_VEX_DECODING_L0_AND_NO_VVVV', ):
3429 for oInstr in self.aoCurInstrs:
3430 if 'vex_l_zero' not in oInstr.dHints:
3431 if oInstr.iLineMnemonicMacro >= 0:
3432 self.errorOnLine(oInstr.iLineMnemonicMacro,
3433 'Missing IEMOPHINT_VEX_L_ZERO! (%s on line %d)' % (sMacro, self.iLine,));
3434 oInstr.dHints['vex_l_zero'] = True;
3435 return True;
3436
3437 #
3438 # IEMOP_MNEMONIC*
3439 #
3440
3441 # IEMOP_MNEMONIC(a_Stats, a_szMnemonic) IEMOP_INC_STATS(a_Stats)
3442 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC');
3443 if asArgs is not None:
3444 if len(self.aoCurInstrs) == 1:
3445 oInstr = self.aoCurInstrs[0];
3446 if oInstr.sStats is None:
3447 oInstr.sStats = asArgs[1];
3448 self.deriveMnemonicAndOperandsFromStats(oInstr, asArgs[1]);
3449
3450 # IEMOP_MNEMONIC0EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
3451 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0EX');
3452 if asArgs is not None:
3453 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[6], asArgs[7],
3454 []);
3455 # IEMOP_MNEMONIC1EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
3456 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1EX');
3457 if asArgs is not None:
3458 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[7], asArgs[8],
3459 [asArgs[6],]);
3460 # IEMOP_MNEMONIC2EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
3461 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2EX');
3462 if asArgs is not None:
3463 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[8], asArgs[9],
3464 [asArgs[6], asArgs[7]]);
3465 # IEMOP_MNEMONIC3EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints, a_fIemHints)
3466 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3EX');
3467 if asArgs is not None:
3468 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[9],
3469 asArgs[10], [asArgs[6], asArgs[7], asArgs[8],]);
3470 # IEMOP_MNEMONIC4EX(a_Stats, a_szMnemonic, a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints,
3471 # a_fIemHints)
3472 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4EX');
3473 if asArgs is not None:
3474 self.workerIemOpMnemonicEx(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], asArgs[10],
3475 asArgs[11], [asArgs[6], asArgs[7], asArgs[8], asArgs[9],]);
3476
3477 # IEMOP_MNEMONIC0(a_Form, a_Upper, a_Lower, a_fDisHints, a_fIemHints)
3478 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC0');
3479 if asArgs is not None:
3480 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[4], asArgs[5], []);
3481 # IEMOP_MNEMONIC1(a_Form, a_Upper, a_Lower, a_Op1, a_fDisHints, a_fIemHints)
3482 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC1');
3483 if asArgs is not None:
3484 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[5], asArgs[6], [asArgs[4],]);
3485 # IEMOP_MNEMONIC2(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_fDisHints, a_fIemHints)
3486 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC2');
3487 if asArgs is not None:
3488 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[6], asArgs[7],
3489 [asArgs[4], asArgs[5],]);
3490 # IEMOP_MNEMONIC3(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_fDisHints, a_fIemHints)
3491 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC3');
3492 if asArgs is not None:
3493 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[7], asArgs[8],
3494 [asArgs[4], asArgs[5], asArgs[6],]);
3495 # IEMOP_MNEMONIC4(a_Form, a_Upper, a_Lower, a_Op1, a_Op2, a_Op3, a_Op4, a_fDisHints, a_fIemHints)
3496 asArgs = self.findAndParseMacroInvocation(sCode, 'IEMOP_MNEMONIC4');
3497 if asArgs is not None:
3498 self.workerIemOpMnemonic(asArgs[0], asArgs[1], asArgs[2], asArgs[3], asArgs[8], asArgs[9],
3499 [asArgs[4], asArgs[5], asArgs[6], asArgs[7],]);
3500
3501 return False;
3502
3503
3504 def parse(self):
3505 """
3506 Parses the given file.
3507 Returns number or errors.
3508 Raises exception on fatal trouble.
3509 """
3510 #self.debug('Parsing %s' % (self.sSrcFile,));
3511
3512 while self.iLine < len(self.asLines):
3513 sLine = self.asLines[self.iLine];
3514 self.iLine += 1;
3515
3516 # We only look for comments, so only lines with a slash might possibly
3517 # influence the parser state.
3518 offSlash = sLine.find('/');
3519 if offSlash >= 0:
3520 if offSlash + 1 >= len(sLine) or sLine[offSlash + 1] != '/' or self.iState != self.kiCode:
3521 offLine = 0;
3522 while offLine < len(sLine):
3523 if self.iState == self.kiCode:
3524 offHit = sLine.find('/*', offLine); # only multiline comments for now.
3525 if offHit >= 0:
3526 self.checkCodeForMacro(sLine[offLine:offHit]);
3527 self.sComment = '';
3528 self.iCommentLine = self.iLine;
3529 self.iState = self.kiCommentMulti;
3530 offLine = offHit + 2;
3531 else:
3532 self.checkCodeForMacro(sLine[offLine:]);
3533 offLine = len(sLine);
3534
3535 elif self.iState == self.kiCommentMulti:
3536 offHit = sLine.find('*/', offLine);
3537 if offHit >= 0:
3538 self.sComment += sLine[offLine:offHit];
3539 self.iState = self.kiCode;
3540 offLine = offHit + 2;
3541 self.parseComment();
3542 else:
3543 self.sComment += sLine[offLine:];
3544 offLine = len(sLine);
3545 else:
3546 assert False;
3547 # C++ line comment.
3548 elif offSlash > 0:
3549 self.checkCodeForMacro(sLine[:offSlash]);
3550
3551 # No slash, but append the line if in multi-line comment.
3552 elif self.iState == self.kiCommentMulti:
3553 #self.debug('line %d: multi' % (self.iLine,));
3554 self.sComment += sLine;
3555
3556 # No slash, but check code line for relevant macro.
3557 elif self.iState == self.kiCode and sLine.find('IEMOP_') >= 0:
3558 #self.debug('line %d: macro' % (self.iLine,));
3559 self.checkCodeForMacro(sLine);
3560
3561 # If the line is a '}' in the first position, complete the instructions.
3562 elif self.iState == self.kiCode and sLine[0] == '}':
3563 #self.debug('line %d: }' % (self.iLine,));
3564 self.doneInstructions();
3565
3566 # Look for instruction table on the form 'IEM_STATIC const PFNIEMOP g_apfnVexMap3'
3567 # so we can check/add @oppfx info from it.
3568 elif self.iState == self.kiCode and sLine.find('PFNIEMOP') > 0 and self.oReFunTable.match(sLine):
3569 self.parseFunctionTable(sLine);
3570
3571 self.doneInstructions();
3572 self.debug('%3s%% / %3s stubs out of %4s instructions in %s'
3573 % (self.cTotalStubs * 100 // self.cTotalInstr, self.cTotalStubs, self.cTotalInstr,
3574 os.path.basename(self.sSrcFile),));
3575 return self.printErrors();
3576
3577
3578def __parseFileByName(sSrcFile, sDefaultMap):
3579 """
3580 Parses one source file for instruction specfications.
3581 """
3582 #
3583 # Read sSrcFile into a line array.
3584 #
3585 try:
3586 oFile = open(sSrcFile, "r"); # pylint: disable=consider-using-with
3587 except Exception as oXcpt:
3588 raise Exception("failed to open %s for reading: %s" % (sSrcFile, oXcpt,));
3589 try:
3590 asLines = oFile.readlines();
3591 except Exception as oXcpt:
3592 raise Exception("failed to read %s: %s" % (sSrcFile, oXcpt,));
3593 finally:
3594 oFile.close();
3595
3596 #
3597 # Do the parsing.
3598 #
3599 try:
3600 cErrors = SimpleParser(sSrcFile, asLines, sDefaultMap).parse();
3601 except ParserException as oXcpt:
3602 print(str(oXcpt));
3603 raise;
3604
3605 return cErrors;
3606
3607
3608def __doTestCopying():
3609 """
3610 Executes the asCopyTests instructions.
3611 """
3612 asErrors = [];
3613 for oDstInstr in g_aoAllInstructions:
3614 if oDstInstr.asCopyTests:
3615 for sSrcInstr in oDstInstr.asCopyTests:
3616 oSrcInstr = g_dAllInstructionsByStat.get(sSrcInstr, None);
3617 if oSrcInstr:
3618 aoSrcInstrs = [oSrcInstr,];
3619 else:
3620 aoSrcInstrs = g_dAllInstructionsByFunction.get(sSrcInstr, []);
3621 if aoSrcInstrs:
3622 for oSrcInstr in aoSrcInstrs:
3623 if oSrcInstr != oDstInstr:
3624 oDstInstr.aoTests.extend(oSrcInstr.aoTests);
3625 else:
3626 asErrors.append('%s:%s: error: @opcopytests reference "%s" matches the destination\n'
3627 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
3628 else:
3629 asErrors.append('%s:%s: error: @opcopytests reference "%s" not found\n'
3630 % ( oDstInstr.sSrcFile, oDstInstr.iLineCreated, sSrcInstr));
3631
3632 if asErrors:
3633 sys.stderr.write(u''.join(asErrors));
3634 return len(asErrors);
3635
3636
3637def __applyOnlyTest():
3638 """
3639 If g_aoOnlyTestInstructions contains any instructions, drop aoTests from
3640 all other instructions so that only these get tested.
3641 """
3642 if g_aoOnlyTestInstructions:
3643 for oInstr in g_aoAllInstructions:
3644 if oInstr.aoTests:
3645 if oInstr not in g_aoOnlyTestInstructions:
3646 oInstr.aoTests = [];
3647 return 0;
3648
3649## List of all main instruction files and their default maps.
3650g_aasAllInstrFilesAndDefaultMap = (
3651 ( 'IEMAllInstructionsOneByte.cpp.h', 'one', ),
3652 ( 'IEMAllInstructionsTwoByte0f.cpp.h', 'two0f', ),
3653 ( 'IEMAllInstructionsThree0f38.cpp.h', 'three0f38', ),
3654 ( 'IEMAllInstructionsThree0f3a.cpp.h', 'three0f3a', ),
3655 ( 'IEMAllInstructionsVexMap1.cpp.h', 'vexmap1', ),
3656 ( 'IEMAllInstructionsVexMap2.cpp.h', 'vexmap2', ),
3657 ( 'IEMAllInstructionsVexMap3.cpp.h', 'vexmap3', ),
3658 ( 'IEMAllInstructions3DNow.cpp.h', '3dnow', ),
3659);
3660
3661def parseAll():
3662 """
3663 Parses all the IEMAllInstruction*.cpp.h files.
3664
3665 Raises exception on failure.
3666 """
3667 sSrcDir = os.path.dirname(os.path.abspath(__file__));
3668 cErrors = 0;
3669 for sName, sDefaultMap in g_aasAllInstrFilesAndDefaultMap:
3670 cErrors += __parseFileByName(os.path.join(sSrcDir, sName), sDefaultMap);
3671 cErrors += __doTestCopying();
3672 cErrors += __applyOnlyTest();
3673
3674 # Total stub stats:
3675 cTotalStubs = 0;
3676 for oInstr in g_aoAllInstructions:
3677 cTotalStubs += oInstr.fStub;
3678 print('debug: %3s%% / %3s stubs out of %4s instructions in total'
3679 % (cTotalStubs * 100 // len(g_aoAllInstructions), cTotalStubs, len(g_aoAllInstructions),));
3680
3681 if cErrors != 0:
3682 raise Exception('%d parse errors' % (cErrors,));
3683 return True;
3684
3685
3686
3687#
3688# Generators (may perhaps move later).
3689#
3690def __formatDisassemblerTableEntry(oInstr):
3691 """
3692 """
3693 sMacro = 'OP';
3694 cMaxOperands = 3;
3695 if len(oInstr.aoOperands) > 3:
3696 sMacro = 'OPVEX'
3697 cMaxOperands = 4;
3698 assert len(oInstr.aoOperands) <= cMaxOperands;
3699
3700 #
3701 # Format string.
3702 #
3703 sTmp = '%s("%s' % (sMacro, oInstr.sMnemonic,);
3704 for iOperand, oOperand in enumerate(oInstr.aoOperands):
3705 sTmp += ' ' if iOperand == 0 else ',';
3706 if g_kdOpTypes[oOperand.sType][2][0] != '%': ## @todo remove upper() later.
3707 sTmp += g_kdOpTypes[oOperand.sType][2].upper(); ## @todo remove upper() later.
3708 else:
3709 sTmp += g_kdOpTypes[oOperand.sType][2];
3710 sTmp += '",';
3711 asColumns = [ sTmp, ];
3712
3713 #
3714 # Decoders.
3715 #
3716 iStart = len(asColumns);
3717 if oInstr.sEncoding is None:
3718 pass;
3719 elif oInstr.sEncoding == 'ModR/M':
3720 # ASSUME the first operand is using the ModR/M encoding
3721 assert len(oInstr.aoOperands) >= 1 and oInstr.aoOperands[0].usesModRM(), "oInstr=%s" % (oInstr,);
3722 asColumns.append('IDX_ParseModRM,');
3723 elif oInstr.sEncoding in [ 'prefix', ]:
3724 for oOperand in oInstr.aoOperands:
3725 asColumns.append('0,');
3726 elif oInstr.sEncoding in [ 'fixed', 'VEX.fixed' ]:
3727 pass;
3728 elif oInstr.sEncoding == 'VEX.ModR/M':
3729 asColumns.append('IDX_ParseModRM,');
3730 elif oInstr.sEncoding == 'vex2':
3731 asColumns.append('IDX_ParseVex2b,')
3732 elif oInstr.sEncoding == 'vex3':
3733 asColumns.append('IDX_ParseVex3b,')
3734 elif oInstr.sEncoding in g_dInstructionMaps:
3735 asColumns.append(g_dInstructionMaps[oInstr.sEncoding].sDisParse + ',');
3736 else:
3737 ## @todo
3738 #IDX_ParseTwoByteEsc,
3739 #IDX_ParseGrp1,
3740 #IDX_ParseShiftGrp2,
3741 #IDX_ParseGrp3,
3742 #IDX_ParseGrp4,
3743 #IDX_ParseGrp5,
3744 #IDX_Parse3DNow,
3745 #IDX_ParseGrp6,
3746 #IDX_ParseGrp7,
3747 #IDX_ParseGrp8,
3748 #IDX_ParseGrp9,
3749 #IDX_ParseGrp10,
3750 #IDX_ParseGrp12,
3751 #IDX_ParseGrp13,
3752 #IDX_ParseGrp14,
3753 #IDX_ParseGrp15,
3754 #IDX_ParseGrp16,
3755 #IDX_ParseThreeByteEsc4,
3756 #IDX_ParseThreeByteEsc5,
3757 #IDX_ParseModFence,
3758 #IDX_ParseEscFP,
3759 #IDX_ParseNopPause,
3760 #IDX_ParseInvOpModRM,
3761 assert False, str(oInstr);
3762
3763 # Check for immediates and stuff in the remaining operands.
3764 for oOperand in oInstr.aoOperands[len(asColumns) - iStart:]:
3765 sIdx = g_kdOpTypes[oOperand.sType][0];
3766 #if sIdx != 'IDX_UseModRM':
3767 asColumns.append(sIdx + ',');
3768 asColumns.extend(['0,'] * (cMaxOperands - (len(asColumns) - iStart)));
3769
3770 #
3771 # Opcode and operands.
3772 #
3773 assert oInstr.sDisEnum, str(oInstr);
3774 asColumns.append(oInstr.sDisEnum + ',');
3775 iStart = len(asColumns)
3776 for oOperand in oInstr.aoOperands:
3777 asColumns.append('OP_PARM_' + g_kdOpTypes[oOperand.sType][3] + ',');
3778 asColumns.extend(['OP_PARM_NONE,'] * (cMaxOperands - (len(asColumns) - iStart)));
3779
3780 #
3781 # Flags.
3782 #
3783 sTmp = '';
3784 for sHint in sorted(oInstr.dHints.keys()):
3785 sDefine = g_kdHints[sHint];
3786 if sDefine.startswith('DISOPTYPE_'):
3787 if sTmp:
3788 sTmp += ' | ' + sDefine;
3789 else:
3790 sTmp += sDefine;
3791 if sTmp:
3792 sTmp += '),';
3793 else:
3794 sTmp += '0),';
3795 asColumns.append(sTmp);
3796
3797 #
3798 # Format the columns into a line.
3799 #
3800 aoffColumns = [4, 29, 49, 65, 77, 89, 109, 125, 141, 157, 183, 199];
3801 sLine = '';
3802 for i, s in enumerate(asColumns):
3803 if len(sLine) < aoffColumns[i]:
3804 sLine += ' ' * (aoffColumns[i] - len(sLine));
3805 else:
3806 sLine += ' ';
3807 sLine += s;
3808
3809 # OP("psrlw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE,
3810 # DISOPTYPE_HARMLESS),
3811 # define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \
3812 # { pszOpcode, idxParse1, idxParse2, idxParse3, 0, opcode, param1, param2, param3, 0, 0, optype }
3813 return sLine;
3814
3815def __checkIfShortTable(aoTableOrdered, oMap):
3816 """
3817 Returns (iInstr, cInstructions, fShortTable)
3818 """
3819
3820 # Determin how much we can trim off.
3821 cInstructions = len(aoTableOrdered);
3822 while cInstructions > 0 and aoTableOrdered[cInstructions - 1] is None:
3823 cInstructions -= 1;
3824
3825 iInstr = 0;
3826 while iInstr < cInstructions and aoTableOrdered[iInstr] is None:
3827 iInstr += 1;
3828
3829 # If we can save more than 30%, we go for the short table version.
3830 if iInstr + len(aoTableOrdered) - cInstructions >= len(aoTableOrdered) // 30:
3831 return (iInstr, cInstructions, True);
3832 _ = oMap; # Use this for overriding.
3833
3834 # Output the full table.
3835 return (0, len(aoTableOrdered), False);
3836
3837def generateDisassemblerTables(oDstFile = sys.stdout):
3838 """
3839 Generates disassembler tables.
3840
3841 Returns exit code.
3842 """
3843
3844 #
3845 # Parse all.
3846 #
3847 try:
3848 parseAll();
3849 except Exception as oXcpt:
3850 print('error: parseAll failed: %s' % (oXcpt,), file = sys.stderr);
3851 return 1;
3852
3853
3854 #
3855 # The disassembler uses a slightly different table layout to save space,
3856 # since several of the prefix varia
3857 #
3858 aoDisasmMaps = [];
3859 for sName, oMap in sorted(iter(g_dInstructionMaps.items()),
3860 key = lambda aKV: aKV[1].sEncoding + ''.join(aKV[1].asLeadOpcodes)):
3861 if oMap.sSelector != 'byte+pfx':
3862 aoDisasmMaps.append(oMap);
3863 else:
3864 # Split the map by prefix.
3865 aoDisasmMaps.append(oMap.copy(oMap.sName, 'none'));
3866 aoDisasmMaps.append(oMap.copy(oMap.sName + '_66', '0x66'));
3867 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F3', '0xf3'));
3868 aoDisasmMaps.append(oMap.copy(oMap.sName + '_F2', '0xf2'));
3869
3870 #
3871 # Dump each map.
3872 #
3873 asHeaderLines = [];
3874 print("debug: maps=%s\n" % (', '.join([oMap.sName for oMap in aoDisasmMaps]),));
3875 for oMap in aoDisasmMaps:
3876 sName = oMap.sName;
3877
3878 if not sName.startswith("vex"): continue; # only looking at the vex maps at the moment.
3879
3880 #
3881 # Get the instructions for the map and see if we can do a short version or not.
3882 #
3883 aoTableOrder = oMap.getInstructionsInTableOrder();
3884 cEntriesPerByte = oMap.getEntriesPerByte();
3885 (iInstrStart, iInstrEnd, fShortTable) = __checkIfShortTable(aoTableOrder, oMap);
3886
3887 #
3888 # Output the table start.
3889 # Note! Short tables are static and only accessible via the map range record.
3890 #
3891 asLines = [];
3892 asLines.append('/* Generated from: %-11s Selector: %-7s Encoding: %-7s Lead bytes opcodes: %s */'
3893 % ( oMap.sName, oMap.sSelector, oMap.sEncoding, ' '.join(oMap.asLeadOpcodes), ));
3894 if fShortTable:
3895 asLines.append('%sconst DISOPCODE %s[] =' % ('static ' if fShortTable else '', oMap.getDisasTableName(),));
3896 else:
3897 asHeaderLines.append('extern const DISOPCODE %s[%d];' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
3898 asLines.append( 'const DISOPCODE %s[%d] =' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
3899 asLines.append('{');
3900
3901 if fShortTable and (iInstrStart & ((0x10 * cEntriesPerByte) - 1)) != 0:
3902 asLines.append(' /* %#04x: */' % (iInstrStart,));
3903
3904 #
3905 # Output the instructions.
3906 #
3907 iInstr = iInstrStart;
3908 while iInstr < iInstrEnd:
3909 oInstr = aoTableOrder[iInstr];
3910 if (iInstr & ((0x10 * cEntriesPerByte) - 1)) == 0:
3911 if iInstr != iInstrStart:
3912 asLines.append('');
3913 asLines.append(' /* %x */' % ((iInstr // cEntriesPerByte) >> 4,));
3914
3915 if oInstr is None:
3916 # Invalid. Optimize blocks of invalid instructions.
3917 cInvalidInstrs = 1;
3918 while iInstr + cInvalidInstrs < len(aoTableOrder) and aoTableOrder[iInstr + cInvalidInstrs] is None:
3919 cInvalidInstrs += 1;
3920 if (iInstr & (0x10 * cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= 0x10 * cEntriesPerByte:
3921 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (0x10 * cEntriesPerByte,));
3922 iInstr += 0x10 * cEntriesPerByte - 1;
3923 elif cEntriesPerByte > 1:
3924 if (iInstr & (cEntriesPerByte - 1)) == 0 and cInvalidInstrs >= cEntriesPerByte:
3925 asLines.append(' INVALID_OPCODE_BLOCK_%u,' % (cEntriesPerByte,));
3926 iInstr += 3;
3927 else:
3928 asLines.append(' /* %#04x/%d */ INVALID_OPCODE,'
3929 % (iInstr // cEntriesPerByte, iInstr % cEntriesPerByte));
3930 else:
3931 asLines.append(' /* %#04x */ INVALID_OPCODE,' % (iInstr));
3932 elif isinstance(oInstr, list):
3933 if len(oInstr) != 0:
3934 asLines.append(' /* %#04x */ ComplicatedListStuffNeedingWrapper, /* \n -- %s */'
3935 % (iInstr, '\n -- '.join([str(oItem) for oItem in oInstr]),));
3936 else:
3937 asLines.append(__formatDisassemblerTableEntry(oInstr));
3938 else:
3939 asLines.append(__formatDisassemblerTableEntry(oInstr));
3940
3941 iInstr += 1;
3942
3943 if iInstrStart >= iInstrEnd:
3944 asLines.append(' /* dummy */ INVALID_OPCODE');
3945
3946 asLines.append('};');
3947 asLines.append('AssertCompile(RT_ELEMENTS(%s) == %s);' % (oMap.getDisasTableName(), iInstrEnd - iInstrStart,));
3948
3949 #
3950 # We always emit a map range record, assuming the linker will eliminate the unnecessary ones.
3951 #
3952 asHeaderLines.append('extern const DISOPMAPDESC %sRange;' % (oMap.getDisasRangeName()));
3953 asLines.append('const DISOPMAPDESC %s = { &%s[0], %#04x, RT_ELEMENTS(%s) };'
3954 % (oMap.getDisasRangeName(), oMap.getDisasTableName(), iInstrStart, oMap.getDisasTableName(),));
3955
3956 #
3957 # Write out the lines.
3958 #
3959 oDstFile.write('\n'.join(asLines));
3960 oDstFile.write('\n');
3961 oDstFile.write('\n');
3962 #break; #for now
3963 return 0;
3964
3965if __name__ == '__main__':
3966 sys.exit(generateDisassemblerTables());
3967
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