VirtualBox

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

Last change on this file since 96860 was 96407, checked in by vboxsync, 21 months ago

scm copyright and license note update

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

© 2023 Oracle
ContactPrivacy policyTerms of Use