VirtualBox

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

Last change on this file since 95522 was 95509, checked in by vboxsync, 3 years ago

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

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