VirtualBox

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

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

Copyright year updates by scm.

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