VirtualBox

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

Last change on this file since 96034 was 95540, checked in by vboxsync, 3 years ago

VMM/IEM: vmovlhps, vmovhps, vmovhpd. bugref:9898

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

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