VirtualBox

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

Last change on this file since 84044 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use