Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: src/trusted/validator_ragel/compress_regular_instructions.py

Issue 49183002: Regular instructions golden file test. Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client/
Patch Set: Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | src/trusted/validator_ragel/testdata/32bit_regular.golden » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright (c) 2013 The Native Client Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 """
6 Traverse the validator's DFA, collect all "normal" instruction and then
7 compress output. Note: "anybyte fields" (immediates and displacements)
8 are always filled with zeros. Otherwise processing of sextillions (sic!)
9 of possibilities will take too long.
10
11 Each rule is applied only when all variants are accepted by validator.
12 The following compression rules are present:
13
14 1. Compress ModR/M (+SIB & displacement).
15 Instruction: 00 00 add %al,(%rax)
16 ...
17 Instruction: 00 ff add %bh,%bh
18 becomes
19 Instruction: 00 XX add [%al..%bh],[%al..%bh or memory]
20
21 1a. Compress ModR/M (+SIB & displacement) memory-only.
22 Instruction: f0 01 00 lock add %eax,(%eax)
23 ...
24 Instruction: f0 01 bf 00 00 00 00 lock add %edi,0x0(%edi)
25 becomes
26 Instruction: f0 01 XX lock add [%eax..edi],[memory]
27
28 1b. Compress ModR/M register only.
29 Instruction: 66 0f 50 c0 movmskpd %xmm0,%eax
30 ...
31 Instruction: 66 0f 50 ff movmskpd %xmm7,%edi
32 becomes
33 Instruction: 66 0f 50 XX movmskpd [%xmm0..%xmm7],[%eax..edi]
34
35 2. Compress ModR/M (+SIB & displacement) with opcode extension.
36 Instruction: 0f 90 00 seto (%eax)
37 ...
38 Instruction: 0f 90 c7 seto %bh
39 becomes
40 Instruction: 0f 90 XX/0 seto [%al..%bh or memory]
41
42 2a. Compress ModR/M (+SIB & displacement) memory-only with opcode extension.
43 Instruction: f0 ff 00 lock incl (%eax)
44 ...
45 Instruction: f0 ff 84 ff 00 00 00 00 lock incl 0x0(%edi,%edi,8)
46 becomes
47 Instruction: f0 ff XX/1 lock decl [memory]
48
49 2b. Compress ModR/M register-only with opcode extension.
50 Instruction: 0f 71 d0 00 psrlw $0x0,%mm0
51 ...
52 Instruction: 0f 71 d7 00 psrlw $0x0,%mm7
53 becomes
54 Instruction: 66 0f 71 XX/2 00 psrlw $0x0,[%mm0..%mm7]
55
56 3. Compress register-in-opcode.
57 Instruction: d9 c0 fld %st(0)
58 ...
59 Instruction: d9 c7 fld %st(7)
60 becomes
61 Instruction: Instruction: d9 c[0..7] fld [%st(0)..%st(7)]
62
63 Only applies if all possible register accesses are accepted by validator.
64
65 4. Special compressor for "set" instruction.
66 Instruction: 0f 90 XX/0 seto [%al..%bh or memory]
67 ...
68 Instruction: 0f 90 XX/7 seto [%al..%bh or memory]
69 becomes
70 Instruction: 0f 90 XX seto [%al..%bh or memory]
71 """
72
73 import itertools
74 import multiprocessing
75 import optparse
76 import os
77 import re
78 import subprocess
79 import sys
80 import tempfile
81 import traceback
82
83 import dfa_parser
84 import dfa_traversal
85 import validator
86
87
88 # Register names in 'natual' order (as defined by IA32/x86-64 ABI)
89 #
90 # X86-64 ABI splits all registers in groups of 8 because it uses 3-bit field
91 # in opcode, ModR/M, and/or SIB bytes to encode them.
92 #
93 # In most cases there are 16 registers of a given kind and two such groups,
94 # but there are couple of exceptions:
95 # 1. There are 20 8-bit registers and three groups (two of them overlap)
96 # 2. There are eight X87 and MMX registers thus two groups are identical
97 #
98 # We use typical register from a group to name the whole group. Most groups
99 # use first register, but 'spl' group uses fifth register because it's first
100 # four registers are the same as 'al' group. We use mnemonic name 'mmalt'
101 # to represent the "evil mirror" of the 'mm0' group.
102 REGISTERS = {
103 'al': [ 'al', 'cl', 'dl', 'bl', 'ah', 'ch', 'dh', 'bh' ],
104 'spl': [ 'al', 'cl', 'dl', 'bl', 'spl', 'bpl', 'sil', 'dil' ],
105 'ax': [ 'ax', 'cx', 'dx', 'bx', 'sp', 'bp', 'si', 'di' ],
106 'eax': [ 'eax', 'ecx', 'edx', 'ebx', 'esp', 'ebp', 'esi', 'edi' ],
107 'rax': [ 'rax', 'rcx', 'rdx', 'rbx', 'rsp', 'rbp', 'rsi', 'rdi' ],
108 'r8b': [ 'r{}b'.format(N) for N in range(8,16) ],
109 'r8w': [ 'r{}w'.format(N) for N in range(8,16) ],
110 'r8d': [ 'r{}d'.format(N) for N in range(8,16) ],
111 'r8': [ 'r{}'.format(N) for N in range(8,16) ],
112 'mm0': [ 'mm{}'.format(N) for N in range(8) ],
113 'mmalt': [ 'mm{}'.format(N) for N in range(8) ],
114 'st(0)': [ 'st({})'.format(N) for N in range(8) ],
115 'xmm0': [ 'xmm{}'.format(N) for N in range(8) ],
116 'xmm8': [ 'xmm{}'.format(N) for N in range(8,16) ],
117 'ymm0': [ 'ymm{}'.format(N) for N in range(8) ],
118 'ymm8': [ 'ymm{}'.format(N) for N in range(8,16) ]
119 }
120
121
122 NOP = 0x90
123
124
125 def PadToBundleSize(bytes):
126 assert len(bytes) <= validator.BUNDLE_SIZE
127 return bytes + [NOP] * (validator.BUNDLE_SIZE - len(bytes))
128
129
130 # In x86-64 mode we have so-called 'restricted register' which is used to
131 # tie two groups together. Some instructions require particular value to
132 # be stored in this variable, while some accept any non-special restricted
133 # register (%ebp and %esp are special because they can only be accepted by
134 # a few 'special' instructions).
135 #
136 # You can find more details in the "NaCl SFI model on x86-64 systems" manual.
137 #
138 # We try to feed all possible 'restricted registers' into validator and then
139 # classify the instruction using this map. If set of acceptable 'restricted
140 # registers' is not here, then it's an error in validator.
141 ACCEPTABLE_X86_64_INPUTS = {
142 0x00001: 'input_rr=%eax',
143 0x00002: 'input_rr=%ecx',
144 0x00004: 'input_rr=%edx',
145 0x00008: 'input_rr=%ebx',
146 0x00010: 'input_rr=%esp',
147 0x00020: 'input_rr=%ebp',
148 0x00040: 'input_rr=%esi',
149 0x00080: 'input_rr=%edi',
150 0x00100: 'input_rr=%r8d',
151 0x00200: 'input_rr=%r9d',
152 0x00400: 'input_rr=%r10d',
153 0x00800: 'input_rr=%r11d',
154 0x01000: 'input_rr=%r12d',
155 0x02000: 'input_rr=%r13d',
156 0x04000: 'input_rr=%r14d',
157 0x08000: 'input_rr=%r15d',
158 0x1ffcf: 'input_rr=any_nonspecial'
159 }
160
161 # Any instruction must produce either None or one of fifteen registers as an
162 # output 'restricted register' value. 'r15d' is NOT acceptable as an output.
163 ACCEPTABLE_X86_64_OUTPUT_REGISTERS = tuple(
164 '%' + reg for reg in (REGISTERS['eax'] + REGISTERS['r8d'])[0:-1])
165
166
167 def ValidateInstruction(instruction, validator_inst):
168 bundle = ''.join(map(chr, PadToBundleSize(instruction)))
169 if options.bitness == 32:
170 result = validator_inst.ValidateChunk(bundle, bitness=32)
171 return result, []
172 else:
173 valid_inputs = 0
174 known_final_rr = None
175 output_rr = None
176 # Note that iteration order is aligned with ACCEPTABLE_X86_64_INPUTS array
177 # above.
178 for bit, initial_rr in enumerate(validator.ALL_REGISTERS + [None]):
179 valid, final_rr = validator_inst.ValidateAndGetFinalRestrictedRegister(
180 bundle, len(instruction), initial_rr)
181 if valid:
182 # final_rr should not depend on input_rr
183 assert valid_inputs == 0 or known_final_rr == final_rr
184 valid_inputs |= 1 << bit
185 known_final_rr = final_rr
186 # If nothing is accepted then instruction is not valid. Easy and simple.
187 if valid_inputs == 0: return False, []
188 # If returned value in unacceptable we'll get IndexError here and this
189 # test will fail
190 if known_final_rr is not None:
191 output_rr = ACCEPTABLE_X86_64_OUTPUT_REGISTERS[known_final_rr]
192 # If collected valid_inputs are unacceptable we'll get KeyError here and
193 # this test will fail
194 return True, [ACCEPTABLE_X86_64_INPUTS[valid_inputs],
195 'output_rr={}'.format(output_rr)]
196
197
198 class WorkerState(object):
199 def __init__(self, prefix, validator):
200 self.total_instructions = 0
201 self.num_valid = 0
202 self.validator = validator
203 self.output = set()
204 self.trace = []
205
206
207 def ReceiveInstruction(self, bytes):
208 self.total_instructions += 1
209 result, notes = ValidateInstruction(bytes, self.validator)
210 if result:
211 self.num_valid += 1
212 dis = self.validator.DisassembleChunk(
213 ''.join(map(chr, bytes)),
214 bitness=options.bitness)
215 for line_nr in xrange(len(dis)):
216 dis[line_nr] = str(dis[line_nr])
217 assert dis[line_nr][0:17] == 'Instruction(0x' + str(line_nr) + ': '
218 assert dis[line_nr][-1:] == ')'
219 dis[line_nr] = dis[line_nr][17:-1]
220 # If %rip is involved then comment will be different depending on the
221 # instruction length. Eliminate it.
222 if '(%rip)' in dis[0]:
223 dis[0] = re.sub(' # 0x[ ]*[0-9a-fA-F]*', '', dis[0])
224 # Zero displacements are represented as 0x0 for all instructions except
225 # jumps where they disassembled as non-zero due to %eip/%rip-relative
226 # addressing. We replace this displacement with %eip/%rip to simplify
227 # compression.
228 if ' 0x' in dis[0] and ' 0x0' not in dis[0]:
229 for bytes in xrange(1, 16):
230 dis[0] = re.sub(
231 '(' + '(?:[0-9a-fA-F][0-9a-fA-F] ){' + str(bytes) + '} .* )' +
232 hex(bytes) + '(.*)',
233 '\\1%eip\\2' if options.bitness == 32 else '\\1%rip\\2',
234 dis[0]);
235 dis[0] = 'Instruction: ' + dis[0]
236 dis += notes
237 self.output.add('; '.join(dis))
238
239
240 def RecordTrace(self, compressor_nr, instruction):
241 self.trace.append((compressor_nr, instruction))
242
243
244 # Compressor has three slots: regex (which picks apart given instruction),
245 # subst (which is used to denote compressed version) and replacements (which
246 # are used to generate set of instructions from a given code).
247 #
248 # Example compressor:
249 # regex = '.*?[0-9a-fA-F]([0-7]) \\w* (%e(?:[abcd]x|[sb]p|[sd]i)).*()'
250 # subst = ('[0-7]', '[%eax..%edi]', ' # register in opcode')
251 # replacements = ((0, '%eax'), (1, '%ecx'), (2, '%edx'), (3, '%ebx')
252 # (4, '%esp'), (5, '%ebp'), (6, '%esi'), (7, '%edi'))
253 #
254 # When faced with instriuction '40 inc %eax' it will capture the following
255 # pieces of said instruction: '4[0] inc [%eax]'.
256 #
257 # Then it will produce the following eight instructions:
258 # '40 inc %eax'
259 # '41 inc %ecx'
260 # '42 inc %edx'
261 # '43 inc %ebx'
262 # '44 inc %esp'
263 # '45 inc %ebp'
264 # '46 inc %esi'
265 # '47 inc %edi'
266 #
267 # If all these instructions can be found in a set of instructions then
268 # compressor will remove them from said set and will insert one replacement
269 # "compressed instruction" '4[0-7] inc [%eax..%edi] # register in opcode'.
270 #
271 # Note that last group is only used in the replacement. It's used to grab marks
272 # added by previous compressors and to replace them with a new mark.
273 class Compressor(object):
274 __slots__ = [
275 'regex',
276 'subst',
277 'replacements'
278 ]
279
280 def __init__(self, regex, subst, replacements=None):
281 self.regex = re.compile(regex)
282 self.subst = subst
283 self.replacements = [] if replacements is None else replacements
284
285
286 def CompressionTemplate(instruction, match, mark):
287 """ Replace all match groups with the mark. """
288 pos = 0
289 format_str = ''
290 for group in range(1, len(match.groups())):
291 format_str += instruction[pos:match.start(group)] + mark
292 pos = match.end(group)
293 return format_str + instruction[pos:match.start(len(match.groups()))]
294
295
296 def CompressOneMatch(instructions, instruction, match, compressor):
297 format_str = CompressionTemplate(instruction, match, '{}')
298 subset = set()
299 for replacement in compressor.replacements:
300 replacement_str = format_str.format(*replacement)
301 if not replacement_str in instructions:
302 return (False, instructions)
303 subset.add(replacement_str)
304 instructions -= subset
305 instructions.add((format_str + '{}').format(*compressor.subst))
306 return (True, instructions)
307
308
309 def CompressOneInstruction(instructions, compressors, split, cache):
310 sorted_instructions = (sorted(i for i in instructions if i > split) +
311 sorted(i for i in instructions if i < split))
312 for instruction in sorted_instructions:
313 if instruction in cache:
314 compressors_list = cache[instruction]
315 for compressor_nr, match, compressor in compressors_list:
316 result, instructions = CompressOneMatch(
317 instructions, instruction, match, compressor)
318 if result:
319 return (instructions, compressor_nr, instruction)
320 else:
321 compressors_list = []
322 for compressor_nr, compressor in enumerate(compressors):
323 match = compressor.regex.match(instruction)
324 if match:
325 compressors_list.append((compressor_nr, match, compressor))
326 result, instructions = CompressOneMatch(
327 instructions, instruction, match, compressor)
328 if result:
329 return (instructions, compressor_nr, instruction)
330 cache[instruction] = compressors_list
331 return (instructions, False, False)
332
333
334 def Compressed(instructions, compressors, show_progress):
335 split = ''
336 cache = {}
337 while True:
338 instructions, rule, split = CompressOneInstruction(
339 instructions, compressors, split, cache)
340 if rule is False: break
341 show_progress(rule, split)
342 return instructions
343
344
345 def Worker((prefix, state_index)):
346 worker_state = WorkerState(prefix, worker_validator)
347
348 try:
349 dfa_traversal.TraverseTree(
350 dfa.states[state_index],
351 final_callback=worker_state.ReceiveInstruction,
352 prefix=prefix,
353 anyfield=0)
354 if (prefix[0] != 0x0f or prefix[1] != 0x0f): # Skip 3DNow! instructions
355 worker_state.output = Compressed(set(worker_state.output),
356 compressors,
357 worker_state.RecordTrace)
358 except Exception as e:
359 traceback.print_exc() # because multiprocessing imap swallows traceback
360 raise
361
362 return (
363 prefix,
364 worker_state.total_instructions,
365 worker_state.num_valid,
366 worker_state.output,
367 worker_state.trace)
368
369
370 def ParseOptions():
371 parser = optparse.OptionParser(usage='%prog [options] xmlfile')
372
373 parser.add_option('--bitness',
374 choices=['32', '64'],
375 help='The subarchitecture: 32 or 64')
376 parser.add_option('--validator_dll',
377 help='Path to librdfa_validator_dll')
378 parser.add_option('--decoder_dll',
379 help='Path to librdfa_decoder_dll')
380
381 options, args = parser.parse_args()
382 options.bitness = int(options.bitness)
383
384 if len(args) != 1:
385 parser.error('specify one xml file')
386
387 (xml_file, ) = args
388
389 return options, xml_file
390
391
392 # Version suitable for use in regular expressions
393 REGISTERS_RE = REGISTERS.copy()
394 REGISTERS_RE['st(0)'] = [ 'st\\({}\\)'.format(N) for N in range(8) ]
395 REGISTERS_RE['st\\(0\\)'] = REGISTERS_RE['st(0)']
396
397 # Index names in 'natual' order (as defined by IA32/x86-64 ABI)
398 INDEXES = {
399 'eax': [ 'eax', 'ecx', 'edx', 'ebx', 'eiz', 'ebp', 'esi', 'edi' ],
400 'rax': [ 'rax', 'rcx', 'rdx', 'rbx', 'riz', 'rbp', 'rsi', 'rdi' ],
401 'r8': [ 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15' ]
402 }
403 # Register which can not be used as base in 64-bit mode in all incarnations
404 X86_64_BASE_REGISTERS = set([
405 '%spl', '%bpl', '%r15b',
406 '%sp', '%bp', '%r15w',
407 '%esp', '%ebp', '%r15d',
408 '%rsp', '%rbp', '%r15',
409 '%rip'
410 ])
411
412 def AddModRMCompressor(regex, subst, subst_register, subst_memory,
413 rm, reg=None, writes_to='rm', opcode_bits=0,
414 memory_accessed=True, register_write='ignore',
415 index_r8=False):
416 """Adds three compressors to the list of compressors:
417 main_compressors (register <-> register or memory instructions)
418 register_compressors (register <-> register instructions)
419 memory_compressors (regsiter <-> memory instructions)
halyavin 2013/11/08 15:35:19 regsiter->register
khim 2013/11/12 10:14:56 This comment is removed
420
421 Args:
422 regex: regular expression for the compressor
423 subst: replacement for register <-> register or memory instructions
424 subst_register: replacement for register <-> register instructions
425 subst_memory: replacement for regsiter <-> memory instructions
426 rm: rm operand kind (see REGISTERS array)
427 reg: reg operand kind (see REGISTERS array) or None if reg is not used
428 writes_to: three-state selector
429 'reg' - instruction uses rm as source, reg as destination
430 'rm' - instruction uses reg as source, rm as destination
431 'both' - instruction writes to both reg and rm
432 opcode_bits: opcode extensions code (used when reg is None)
433 memory_accessed: True if instruction accesses memory
434 register_write: three-state selector
435 'sandbox' - instruction can be used to produce "restricted register"
436 'protect' - instruction can damage output, protect "special registers"
437 'ignore' - instruction does not affect it's operands (e.g. test) or
438 is used with non-GP registers (X87, MMX, XMM, etc)
439 Internal:
440 index_r8: must not be set by external users (used to create two compressors
441 in 64-bit mode with index == %rax..%rdi or index == %r8..%r14)
442 Returns:
443 None
444 """
445
446 # Expand RR_NOTES section in regex.
447 if options.bitness == 32:
448 base = 'eax'
449 index = 'eax'
450 expanded_regex = re.sub('{RR_NOTES}', '', regex)
451 else:
452 base = 'r8' if '8' in rm or rm == 'mmalt' else 'rax'
453 index = 'r8' if index_r8 else 'rax'
454 input = 'r8d' if index_r8 else 'eax'
455 if register_write == 'sandbox':
456 output_regs = reg if writes_to == 'reg' else rm
457 assert output_regs in ('eax', 'r8d')
458 expanded_regex = re.sub('{RR_NOTES}',
459 '; input_rr=((?:%{'+ input + '}|any_nonspecial))'
460 '; output_rr=(%{' + output_regs + '}|None)', regex)
461 else:
462 expanded_regex = re.sub('{RR_NOTES}',
463 '; input_rr=((?:%{' + input + '}|any_nonspecial));'
464 ' output_rr=(None)', regex)
465 if 'RM_BYTE' in regex:
466 address_regex = '(?:0x0|(?:0x0)?\\((?:%{' + base + '})\\))'
467 else:
468 address_regex = ('(?:0x0|(?:0x0)?'
469 '\\('
470 '(?:%{' + base + '})?'
471 '(?:,(?:%{' + index + '}))?'
472 '(?:,(?:1|2|4|8))?'
473 '\\))')
474
475 # We need to process either modrm or reg
476 assert rm is not None or reg is not None
477 # If both modrm and reg are given then opcode_bits should not be used
478 assert reg is None or opcode_bits == 0
479 # Replace RM_BYTE placeholders.
480 # Handle only cases without displacement.
481 expanded_regex = re.sub('{RM_BYTE}', '[0-9a-fA-F][0-9a-fA-F]', expanded_regex)
482 expanded_regex = re.sub('{RM_BYTE/0}', '[048cC][0-7]', expanded_regex)
483 expanded_regex = re.sub('{RM_BYTE/1}', '[048cC][89a-fA-F]', expanded_regex)
484 expanded_regex = re.sub('{RM_BYTE/2}', '[159dD][0-7]', expanded_regex)
485 expanded_regex = re.sub('{RM_BYTE/3}', '[159dD][89a-fA-F]', expanded_regex)
486 expanded_regex = re.sub('{RM_BYTE/4}', '[26aAeE][0-7]', expanded_regex)
487 expanded_regex = re.sub('{RM_BYTE/5}', '[26aAeE][89a-fA-F]', expanded_regex)
488 expanded_regex = re.sub('{RM_BYTE/6}', '[37bBfF][0-7]', expanded_regex)
489 expanded_regex = re.sub('{RM_BYTE/7}', '[37bBfF][89a-fA-F]', expanded_regex)
490 register_regex = expanded_regex
491 # Replace RM_SIB_BYTES placeholders.
492 # Handle only cases without displacement.
493 expanded_regex = re.sub(
494 '{RM_SIB_BYTES}', '[0-b][4c] [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
495 expanded_regex = re.sub(
496 '{RM_SIB_BYTES/0}', '[048]4 [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
497 expanded_regex = re.sub(
498 '{RM_SIB_BYTES/1}', '[048][cC] [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
499 expanded_regex = re.sub(
500 '{RM_SIB_BYTES/2}', '[159]4 [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
501 expanded_regex = re.sub(
502 '{RM_SIB_BYTES/3}', '[159][cC] [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
503 expanded_regex = re.sub(
504 '{RM_SIB_BYTES/4}', '[26aA]4 [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
505 expanded_regex = re.sub(
506 '{RM_SIB_BYTES/5}', '[26aA][cC] [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
507 expanded_regex = re.sub(
508 '{RM_SIB_BYTES/6}', '[37bB]4 [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
509 expanded_regex = re.sub(
510 '{RM_SIB_BYTES/7}', '[37bB][cC] [0-9a-fA-F][0-9a-fA-F]', expanded_regex)
511 register_regex = re.sub(
512 '{RM_SIB_BYTES}', '[c-fC-F][0-9a-fA-F]', register_regex)
513 register_regex = re.sub('{RM_SIB_BYTES/0}', '[cC][0-7]', register_regex)
514 register_regex = re.sub('{RM_SIB_BYTES/1}', '[cC][8-9a-fA-F]', register_regex)
515 register_regex = re.sub('{RM_SIB_BYTES/2}', '[dD][0-7]', register_regex)
516 register_regex = re.sub('{RM_SIB_BYTES/3}', '[dD][8-9a-fA-F]', register_regex)
517 register_regex = re.sub('{RM_SIB_BYTES/4}', '[eE][0-7]', register_regex)
518 register_regex = re.sub('{RM_SIB_BYTES/5}', '[eE][8-9a-fA-F]', register_regex)
519 register_regex = re.sub('{RM_SIB_BYTES/6}', '[fF][0-7]', register_regex)
520 register_regex = re.sub('{RM_SIB_BYTES/7}', '[fF][8-9a-fA-F]', register_regex)
521 # Replace register placeholders
522 for register, value in REGISTERS_RE.iteritems():
523 expanded_regex = re.sub('{%' + register + '}',
524 '(?:%' + '|%'.join(value) + '|' + address_regex +')', expanded_regex)
halyavin 2013/11/08 15:35:19 It is better to have context-independent language.
halyavin 2013/11/08 15:35:19 Create a single array and join it via '|'.join(...
khim 2013/11/12 10:14:56 Not sure why, but this language is removed, we are
khim 2013/11/12 10:14:56 This logic is also removed
525 register_regex = re.sub('{%' + register + '}',
526 '(?:%' + '|%'.join(value) +')', register_regex)
527 for register, value in REGISTERS_RE.iteritems():
528 expanded_regex = re.sub('{' + register + '}',
529 '(?:' + '|'.join(value) + ')', expanded_regex)
530 register_regex = re.sub('{' + register + '}',
531 '(?:' + '|'.join(value) + ')', register_regex)
halyavin 2013/11/08 15:35:19 It makes sense to extract this template language i
khim 2013/11/12 10:14:56 Language is removed: we accept all variants here n
532 # Add index_rr and output_rr fields if we are dealing with 64-bit case
533 if options.bitness == 32:
534 subst_fixed = subst
535 subst_register_fixed = subst_register
536 subst_memory_fixed = subst_memory
537 else:
538 if memory_accessed:
539 input_note = '[%eax..%edi]' if index == 'rax' else '[%r8d..%r15d]'
540 else:
541 input_note = 'any_nonspecial'
542 if register_write == 'sandbox':
543 output_note = '[%eax..%edi]' if output_regs == 'eax' else '[%r8d..%r14d]'
544 else:
545 output_note = None
546 subst_fixed = subst[0:-1] + (input_note, output_note) + subst[-1:]
547 subst_register_fixed = subst_register[0:-1] + (
548 'any_nonspecial', output_note) + subst_register[-1:]
549 subst_memory_fixed = subst_memory[0:-1] + (input_note,
550 output_note) + subst_memory[-1:]
551 # If we already have replacements in cache then wejust reuse them.
552 output_key = (reg, rm, writes_to, opcode_bits, index_r8,
553 memory_accessed, register_write)
554 if output_key in AddModRMCompressor.replacements:
555 replacements = AddModRMCompressor.replacements[output_key]
556 main_compressors.append(
557 Compressor(expanded_regex, subst_fixed, replacements[0]))
558 register_compressors.append(
559 Compressor(register_regex, subst_register_fixed, replacements[1]))
560 memory_compressors.append(
561 Compressor(expanded_regex, subst_memory_fixed, replacements[2]))
562 if options.bitness == 64 and not index_r8:
563 AddModRMCompressor(
564 regex, subst, subst_register, subst_memory,
565 reg=reg, rm=rm, writes_to=writes_to, opcode_bits=opcode_bits,
566 index_r8=True, memory_accessed=memory_accessed,
567 register_write=register_write)
568 return
569 # It can be memory only instruction, register only one or both
570 main_compressor = Compressor(expanded_regex, subst_fixed)
571 register_compressor = Compressor(register_regex, subst_register_fixed)
572 memory_compressor = Compressor(expanded_regex, subst_memory_fixed)
573
574 # Generation time! Use reversed ranges to check unlikely cases first.
575 if reg is None:
576 # reg field is used as opcode extension
577 byte_range = [byte
578 for byte in range(0xff, -1, -1)
579 if byte & 0x38 == opcode_bits << 3]
580 else:
581 byte_range = range(0xff, -1, -1)
582
583 for modrm in byte_range:
584 # Parse ModRM
585 mod_field = (modrm & 0xc0) >> 6
586 reg_field = (modrm & 0x38) >> 3
587 rm_field = (modrm & 0x07)
588 if reg is not None:
589 reg_text = '%' + REGISTERS[reg][reg_field]
590 # If mod == 3 then it's register-to-register instruction
591 if mod_field == 3:
592 bytes = '{:02x}'.format(modrm)
593 rm_text = '%' + REGISTERS[rm][rm_field]
594 replacement = [bytes]
595 if reg is None:
596 replacement.append(rm_text)
597 else:
598 replacement.append(rm_text if writes_to == 'reg' else reg_text)
599 replacement.append(reg_text if writes_to == 'reg' else rm_text)
600 if options.bitness == 64:
601 replacement.append('any_nonspecial')
602 output = reg_text if writes_to == 'reg' else rm_text
603 replacement.append(output if register_write == 'sandbox' else None)
604 if register_write == 'protect' and output in X86_64_BASE_REGISTERS:
605 continue
606 if register_write == 'sandbox' and output == '%r15d':
607 continue
608 if writes_to == 'both' and reg_text in X86_64_BASE_REGISTERS:
609 continue
610 replacement = tuple(replacement)
611 main_compressor.replacements.append(replacement)
612 register_compressor.replacements.append(replacement)
613 # If mod != 3 then it's register-to-memory instruction
614 else:
615 # If RM field != %rsp then there are no index
616 if rm_field != validator.REG_RSP:
617 base_text = '%' + REGISTERS[base][rm_field]
618 # If RM field == %rbp and MOD fiels is zero then it's absolute address
619 if mod_field == 0 and rm_field == validator.REG_RBP:
620 bytes = '{:02x} 00 00 00 00'.format(modrm)
621 rm_text = '0x0' if options.bitness == 32 else '0x0(%rip)'
622 base_text = '%rip'
623 # Memory access with just a base register
624 elif mod_field == 0:
625 bytes = '{:02x}'.format(modrm)
626 rm_text = '({})'.format(base_text)
627 # Memory access with base and 8bit offset
628 elif mod_field == 1:
629 bytes = '{:02x} 00'.format(modrm)
630 rm_text = '0x0({})'.format(base_text)
631 # Memory access with base and 32bit offset
632 else: # mod_field == 2
633 bytes = '{:02x} 00 00 00 00'.format(modrm)
634 rm_text = '0x0({})'.format(base_text)
635 replacement = [bytes]
636 if reg is None:
637 replacement.append(rm_text)
638 else:
639 replacement.append(rm_text if writes_to == 'reg' else reg_text)
640 replacement.append(reg_text if writes_to == 'reg' else rm_text)
641 if options.bitness == 64:
642 replacement.append('any_nonspecial')
643 output = reg_text if writes_to == 'reg' else None
644 replacement.append(output if register_write == 'sandbox' else None)
645 if memory_accessed and base_text not in X86_64_BASE_REGISTERS:
646 continue
647 if register_write == 'protect' and output in X86_64_BASE_REGISTERS:
648 continue
649 if register_write == 'sandbox' and output == '%r15d':
650 continue
651 if writes_to == 'both' and reg_text in X86_64_BASE_REGISTERS:
652 continue
653 replacement = tuple(replacement)
654 main_compressor.replacements.append(replacement)
655 memory_compressor.replacements.append(replacement)
656 else:
657 # If RM field == %rsp then we have SIB byte
658 for sib in xrange(0x100):
659 scale_field = (sib & 0xc0) >> 6
660 index_field = (sib & 0x38) >> 3
661 base_field = (sib & 0x07)
662 index_text = '%' + INDEXES[index][index_field]
663 base_text = '%' + REGISTERS[base][base_field]
664 scale_text = pow(2, scale_field)
665 # If BASE is %rbp and MOD == 0 then index with 32bit offset is used
666 if mod_field == 0 and base_field == validator.REG_RBP:
667 bytes = '{:02x} {:02x} 00 00 00 00'.format(modrm, sib)
668 if (options.bitness == 32 or
669 index_field != validator.REG_RSP or
670 scale_field != 0 or index[0:2] == 'r8'):
671 rm_text = '0x0(,{},{})'.format(index_text, scale_text)
672 else:
673 rm_text = '0x0'
674 base_text = ''
675 # Memory access with base and index (no offset)
676 elif mod_field == 0:
677 bytes = '{:02x} {:02x}'.format(modrm, sib)
678 rm_text = '({},{},{})'.format(base_text, index_text, scale_text)
679 # Memory access with base, index and 8bit offset
680 elif mod_field == 1:
681 bytes = '{:02x} {:02x} 00'.format(modrm, sib)
682 rm_text = '0x0({},{},{})'.format(base_text, index_text, scale_text)
683 # Memory access with base, index and 32bit offset
684 elif mod_field == 2:
685 bytes = '{:02x} {:02x} 00 00 00 00'.format(modrm, sib)
686 rm_text = '0x0({},{},{})'.format(base_text, index_text, scale_text)
687 # Pretty-printing of access via %rsp
688 if (scale_field == 0 and index != 'r8' and
689 base_field == validator.REG_RSP and
690 index_field == validator.REG_RSP):
691 #index_text = 'any_nonspecial'
692 rm_text = ('0x0({})' if mod_field else '({})').format(base_text)
693 if index_text == "%riz":
694 index_text = 'any_nonspecial'
695 replacement = [bytes]
696 if reg is None:
697 replacement.append(rm_text)
698 else:
699 replacement.append(rm_text if writes_to == 'reg' else reg_text)
700 replacement.append(reg_text if writes_to == 'reg' else rm_text)
701 if options.bitness == 64:
702 if not memory_accessed or index_text == 'any_nonspecial':
703 replacement.append('any_nonspecial')
704 else:
705 replacement.append('%' + REGISTERS[input][index_field])
706 # Currently xchg can not used used for sandboxing
707 output = reg_text if writes_to == 'reg' else None
708 replacement.append(output if register_write == 'sandbox' else None)
709 if memory_accessed:
710 if base_text not in X86_64_BASE_REGISTERS: continue
711 if index_text in X86_64_BASE_REGISTERS - set(['%r15']): continue
712 if register_write == 'protect' and output in X86_64_BASE_REGISTERS:
713 continue
714 if register_write == 'sandbox' and output == '%r15d':
715 continue
716 if (writes_to == 'both' and
717 reg_text in X86_64_BASE_REGISTERS): continue
718 replacement = tuple(replacement)
719 main_compressor.replacements.append(replacement)
720 memory_compressor.replacements.append(replacement)
721
722 assert len(main_compressor.replacements) > 1
723 assert len(register_compressor.replacements) > 1
724 assert len(memory_compressor.replacements) > 1
725 main_compressor.replacements = tuple(main_compressor.replacements)
726 register_compressor.replacements = tuple(register_compressor.replacements)
727 memory_compressor.replacements = tuple(memory_compressor.replacements)
728 main_compressors.append(main_compressor)
729 register_compressors.append(register_compressor)
730 memory_compressors.append(memory_compressor)
731 AddModRMCompressor.replacements[output_key] = (
732 main_compressor.replacements,
733 register_compressor.replacements,
734 memory_compressor.replacements
735 )
736 if options.bitness == 64 and not index_r8:
737 AddModRMCompressor(
738 regex, subst, subst_register, subst_memory,
739 reg=reg, rm=rm, writes_to=writes_to, opcode_bits=opcode_bits,
740 index_r8=True, memory_accessed=memory_accessed,
741 register_write=register_write)
742 # Replacements cache.
743 AddModRMCompressor.replacements = {}
744
745
746 def PrepareCompressors():
747 global compressors
748 global main_compressors
749 global register_compressors
750 global memory_compressors
751
752 # "Larger" compressors should be tried first, then "smaller" ones.
753 main_compressors = []
754 register_compressors = []
755 memory_compressors = []
756 extra_compressors = []
757
758 if options.bitness == 32:
759 register_kinds = ('al', 'ax', 'eax', 'mm0', 'xmm0', 'ymm0')
760 register_kind_pairs = (
761 ( 'al', 'al'),
762 ( 'ax', 'al'),
763 ( 'ax', 'ax'),
764 ( 'eax', 'al'),
765 ( 'eax', 'ax'),
766 ( 'eax', 'eax'),
767 ( 'eax', 'mm0'),
768 ( 'mm0', 'eax'),
769 ( 'eax', 'xmm0'),
770 ('xmm0', 'eax'),
771 ( 'mm0', 'mm0'),
772 ( 'mm0', 'xmm0'),
773 ('xmm0', 'mm0'),
774 ('xmm0', 'xmm0'),
775 ('xmm0', 'ymm0'),
776 ('ymm0', 'xmm0'),
777 ('ymm0', 'ymm0')
778 )
779 else:
780 register_kinds = ('al', 'spl', 'ax', 'eax', 'rax', 'mm0', 'xmm0', 'ymm0',
781 'r8b', 'r8w', 'r8d', 'r8', 'mmalt', 'xmm8', 'ymm8')
782 register_kind_pairs = (
783 ( 'al', 'al'),
784 ( 'spl', 'spl'), ( 'spl', 'r8b'), ( 'r8b', 'spl'), ( 'r8b', 'r8b'),
785 ( 'ax', 'al'),
786 ( 'ax', 'spl'), ( 'ax', 'r8b'), ( 'r8w', 'spl'), ( 'r8w', 'r8b'),
787 ( 'ax', 'ax'), ( 'ax', 'r8w'), ( 'r8w', 'ax'), ( 'r8w', 'r8w'),
788 ( 'eax', 'al'),
789 ( 'eax', 'spl'), ( 'eax', 'r8b'), ( 'r8d', 'spl'), ( 'r8d', 'r8b'),
790 ( 'eax', 'ax'), ( 'eax', 'r8w'), ( 'r8d', 'ax'), ( 'r8d', 'r8w'),
791 ( 'eax', 'eax'), ( 'eax', 'r8d'), ( 'r8d', 'eax'), ( 'r8d', 'r8d'),
792 ( 'rax', 'al'),
793 ( 'rax', 'spl'), ( 'rax', 'r8b'), ( 'r8', 'spl'), ( 'r8', 'r8b'),
794 ( 'rax', 'ax'), ( 'rax', 'r8w'), ( 'r8', 'ax'), ( 'r8', 'r8w'),
795 ( 'rax', 'eax'), ( 'rax', 'r8d'), ( 'r8', 'eax'), ( 'r8', 'r8d'),
796 ( 'rax', 'rax'), ( 'rax', 'r8'), ( 'r8', 'rax'), ( 'r8', 'r8'),
797 ( 'eax', 'mm0'), ( 'eax','mmalt'), ( 'r8d', 'mm0'), ( 'eax', 'mmalt'),
798 ( 'rax', 'mm0'), ( 'rax','mmalt'), ( 'r8', 'mm0'), ( 'r8', 'mmalt'),
799 ( 'mm0', 'eax'), ('mmalt', 'eax'), ( 'mm0', 'r8d'), ('mmalt', 'r8d'),
800 ( 'mm0', 'rax'), ('mmalt', 'rax'), ( 'mm0', 'r8'), ('mmalt', 'r8'),
801 ( 'eax', 'xmm0'), ( 'eax', 'xmm8'), ( 'r8d', 'xmm0'), ( 'r8d', 'xmm8'),
802 ( 'rax', 'xmm0'), ( 'rax', 'xmm8'), ( 'r8', 'xmm0'), ( 'r8', 'xmm8'),
803 ('xmm0', 'eax'), ('xmm0', 'r8d'), ('xmm8', 'eax'), ('xmm8', 'r8d'),
804 ('xmm0', 'rax'), ('xmm0', 'r8'), ('xmm8', 'rax'), ('xmm8', 'r8'),
805 ( 'mm0', 'mm0'), ('mmalt', 'mm0'), ( 'mm0','mmalt'), ('mmalt','mmalt'),
806 ( 'mm0', 'xmm0'), ('mmalt','xmm0'), ( 'mm0', 'xmm8'), ('mmalt', 'xmm8'),
807 ('xmm0', 'mm0'), ('xmm8', 'mm0'), ('xmm0','mmalt'), ('xmm8', 'mmalt'),
808 ('xmm0', 'xmm0'), ('xmm0', 'xmm8'), ('xmm8', 'xmm0'), ('xmm8', 'xmm8'),
809 ('xmm0', 'ymm0'), ('xmm0', 'ymm8'), ('xmm8', 'ymm0'), ('xmm8', 'ymm8'),
810 ('ymm0', 'xmm0'), ('ymm0', 'xmm8'), ('ymm8', 'xmm0'), ('ymm8', 'xmm8'),
811 ('ymm0', 'ymm0'), ('ymm0', 'ymm8'), ('ymm8', 'ymm0'), ('ymm8', 'ymm8')
812 )
813
814 # Largest compressors: both reg and rm fields are used
815 for reg, rm in register_kind_pairs:
816 start_reg = REGISTERS[reg][0]
817 end_reg = REGISTERS[reg][-1 if reg[0:2] != 'r8' else -2]
818 start_rm = REGISTERS[rm][0]
819 end_rm = REGISTERS[rm][-1 if rm[0:2] != 'r8' else -2]
820 # First instruction uses just ModR/M byte in 32bit mode but both
821 # ModR/M in 64bit mode. Both approaches will work in both cases,
822 # this is just an optimization to avoid needless work.
823 if options.bitness == 32:
824 bytes = '({RM_BYTE})'
825 else:
826 bytes = '({RM_SIB_BYTES})'
827 for extra_bytes in ('', ' 00', ' 00 00', ' 00 00 00 00'):
828 # Lea in 64 bit mode is truly unique instruction for now
829 if options.bitness == 64 and reg in ('eax', 'r8d', 'rax', 'r8'):
830 AddModRMCompressor(
831 '.*?' + bytes + extra_bytes +
832 ' (?:lock )?\\w* (?:\\$0x0,|\\$0x0,\\$0x0,|%cl,|%xmm0,)?'
833 '({%' + rm + '}),(%{' + reg + '}).*{RR_NOTES}()',
834 ('XX', '[%{}..%{} or memory]'.format(start_rm, end_rm),
835 '[%{}..%{}]'.format(start_reg, end_reg), ' # lea'),
836 ('XX', '[%{}..%{}]'.format(start_rm, end_rm),
837 '[%{}..%{}]'.format(start_reg, end_reg), ' # rm to reg; lea'),
838 ('XX', '[memory]', '[%{}..%{}]'.format(start_reg, end_reg), ' # lea'),
839 reg=reg, rm=rm, writes_to='reg', memory_accessed=False,
840 register_write='sandbox' if reg in ('eax', 'r8d') else 'protect')
841 # Normal instructions with two operands (rm to reg).
842 AddModRMCompressor(
843 '.*?' + bytes + extra_bytes +
844 ' (?:lock )?\\w* (?:\\$0x0,|\\$0x0,\\$0x0,|%cl,|%xmm0,)?'
845 '({%' + rm + '}),(%{' + reg + '}).*{RR_NOTES}()',
846 ('XX', '[%{}..%{} or memory]'.format(start_rm, end_rm),
847 '[%{}..%{}]'.format(start_reg, end_reg), ''),
848 ('XX', '[%{}..%{}]'.format(start_rm, end_rm),
849 '[%{}..%{}]'.format(start_reg, end_reg), ' # rm to reg'),
850 ('XX', '[memory]', '[%{}..%{}]'.format(start_reg, end_reg), ''),
851 reg=reg, rm=rm, writes_to='reg')
852 # Normal instructions with two operands (reg to rm).
853 AddModRMCompressor(
854 '.*?' + bytes + extra_bytes +
855 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
856 '(%{' + reg + '}),({%' + rm + '}).*{RR_NOTES}()',
857 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
858 '[%{}..%{} or memory]'.format(start_rm, end_rm), ''),
859 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
860 '[%{}..%{}]'.format(start_rm, end_rm), ' # reg to rm'),
861 ('XX', '[%{}..%{}]'.format(start_reg, end_reg), '[memory]', ''),
862 reg=reg, rm=rm, writes_to='rm')
863 # There are few more forms in 64 bit case (rm to reg).
864 if options.bitness == 64 and reg in ('eax', 'r8d'):
865 # Zero-extending version.
866 AddModRMCompressor(
867 '.*?' + bytes + extra_bytes +
868 ' (?:lock )?\\w* (?:\\$0x0,|\\$0x0,\\$0x0,|%cl,|%xmm0,)?'
869 '({%' + rm + '}),(%{' + reg + '}).*{RR_NOTES}()',
870 ('XX', '[%{}..%{} or memory]'.format(start_rm, end_rm),
871 '[%{}..%{}]'.format(start_reg, end_reg), ''),
872 ('XX', '[%{}..%{}]'.format(start_rm, end_rm),
873 '[%{}..%{}]'.format(start_reg, end_reg), ' # rm to reg'),
874 ('XX', '[memory]', '[%{}..%{}]'.format(start_reg, end_reg), ''),
875 reg=reg, rm=rm, writes_to='reg', register_write='sandbox')
876 # More forms in 64 bit case (reg to rm).
877 if options.bitness == 64 and rm in ('eax', 'r8d'):
878 # Zero-extending version.
879 AddModRMCompressor(
880 '.*?' + bytes + extra_bytes +
881 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
882 '(%{' + reg + '}),({%' + rm + '}).*{RR_NOTES}()',
883 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
884 '[%{}..%{} or memory]'.format(start_rm, end_rm), ''),
885 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
886 '[%{}..%{}]'.format(start_rm, end_rm), ' # reg to rm'),
887 ('XX', '[%{}..%{}]'.format(start_reg, end_reg), '[memory]', ''),
888 reg=reg, rm=rm, writes_to='rm', register_write='sandbox')
889 # Zero-extending xchg/xadd.
890 AddModRMCompressor(
891 '.*?' + bytes + extra_bytes +
892 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
893 '(%{' + reg + '}),({%' + rm + '}).*{RR_NOTES}()',
894 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
895 '[%{}..%{} or memory]'.format(start_rm, end_rm),
896 ' # write to both'),
897 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
898 '[%{}..%{}]'.format(start_rm, end_rm),
899 ' # reg to rm; write to both'),
900 ('XX', '[%{}..%{}]'.format(start_reg, end_reg), '[memory]',
901 ' # write to both'),
902 reg=reg, rm=rm, writes_to='both', register_write='sandbox')
903 # Still more forms for 64 bit case (rm to reg).
904 if options.bitness == 64 and reg in ('al', 'spl', 'ax', 'eax', 'rax',
905 'r8b', 'r8w', 'r8d', 'r8'):
906 # Dangerous instructions (rm to reg).
907 AddModRMCompressor(
908 '.*?' + bytes + extra_bytes +
909 ' (?:lock )?\\w* (?:\\$0x0,|\\$0x0,\\$0x0,|%cl,|%xmm0,)?'
910 '({%' + rm + '}),(%{' + reg + '}).*{RR_NOTES}()',
911 ('XX', '[%{}..%{} or memory]'.format(start_rm, end_rm),
912 '[%{}..%{}]'.format(start_reg, end_reg), ''),
913 ('XX', '[%{}..%{}]'.format(start_rm, end_rm),
914 '[%{}..%{}]'.format(start_reg, end_reg), ' # rm to reg'),
915 ('XX', '[memory]', '[%{}..%{}]'.format(start_reg, end_reg), ''),
916 reg=reg, rm=rm, writes_to='reg', register_write='protect')
917 # Still more forms for 64 bit case (reg to rm).
918 if options.bitness == 64 and rm in ('al', 'spl', 'ax', 'eax', 'rax',
919 'r8b', 'r8w', 'r8d', 'r8'):
920 # Dangerous instructions (reg to rm).
921 AddModRMCompressor(
922 '.*?' + bytes + extra_bytes +
923 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
924 '(%{' + reg + '}),({%' + rm + '}).*{RR_NOTES}()',
925 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
926 '[%{}..%{} or memory]'.format(start_rm, end_rm), ''),
927 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
928 '[%{}..%{}]'.format(start_rm, end_rm), ' # reg to rm'),
929 ('XX', '[%{}..%{}]'.format(start_reg, end_reg), '[memory]', ''),
930 reg=reg, rm=rm, writes_to='rm', register_write='protect')
931 # Dangerous xchg/xadd.
932 AddModRMCompressor(
933 '.*?' + bytes + extra_bytes +
934 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
935 '(%{' + reg + '}),({%' + rm + '}).*{RR_NOTES}()',
936 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
937 '[%{}..%{} or memory]'.format(start_rm, end_rm),
938 ' # write to both'),
939 ('XX', '[%{}..%{}]'.format(start_reg, end_reg),
940 '[%{}..%{}]'.format(start_rm, end_rm),
941 ' # reg to rm; write to both'),
942 ('XX', '[%{}..%{}]'.format(start_reg, end_reg), '[memory]',
943 ' # write to both'),
944 reg=reg, rm=rm, writes_to='both', register_write='protect')
945 # 3DNow! instructions. Additional byte is opcode extension.
946 AddModRMCompressor(
947 '.*?' + bytes + ' [0-9a-fA-F][0-9a-fA-F] \\w* '
948 '({%' + rm + '}),(%{' + reg + '}).*{RR_NOTES}()',
949 ('XX', '[%{}..%{} or memory]'.format(start_rm, end_rm),
950 '[%{}..%{}]'.format(start_reg, end_reg), ''),
951 ('XX', '[%{}..%{}]'.format(start_rm, end_rm),
952 '[%{}..%{}]'.format(start_reg, end_reg), ' # reg to rm'),
953 ('XX', '[memory]', '[%{}..%{}]'.format(start_reg, end_reg), ''),
954 reg=reg, rm=rm, writes_to='reg')
955
956 # Smaller compressors: only rm field is used.
957 for rm in register_kinds:
958 start_rm = REGISTERS[rm][0]
959 end_rm = REGISTERS[rm][-1 if rm[0:2] != 'r8' else -2]
960 for opcode_bits in xrange(8):
961 XX_byte_mark = 'XX/' + str(opcode_bits)
962 # First instruction uses just ModR/M byte in 32bit mode but both
963 # ModR/M in 64bit mode. Both approaches will work in both cases,
964 # this is just an optimization to avoid needless work.
965 if options.bitness == 32:
966 bytes = '({RM_BYTE/' + str(opcode_bits) + '})'
967 else:
968 bytes = '({RM_SIB_BYTES/' + str(opcode_bits) + '})'
969 if options.bitness == 64:
970 # No memory access (e.g. prefetch)
971 AddModRMCompressor(
972 '.*?' + bytes + ' ?\\w* (?:\\$0x0,|%cl,)?({%' + rm + '}).*'
973 '{RR_NOTES}()',
974 (XX_byte_mark, '[%{}..%{} or memory]'.format(start_rm, end_rm), ''),
975 (XX_byte_mark, '[%{}..%{}]'.format(start_rm, end_rm), ''),
976 (XX_byte_mark, '[memory]', ''),
977 reg=None, rm=rm, memory_accessed=False, opcode_bits=opcode_bits)
978 for extra_bytes in ('', ' 00', ' 00 00', ' 00 00 00 00'):
979 # Part of opcode is encoded in ModR/M
980 AddModRMCompressor(
981 '.*?' + bytes + extra_bytes +
982 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
983 '({%' + rm + '}).*{RR_NOTES}()',
984 (XX_byte_mark, '[%{}..%{} or memory]'.format(start_rm, end_rm), ''),
985 (XX_byte_mark, '[%{}..%{}]'.format(start_rm, end_rm), ''),
986 (XX_byte_mark, '[memory]', ''),
987 reg=None, rm=rm, opcode_bits=opcode_bits)
988 # More forms in 64 bit case.
989 if options.bitness == 64 and rm in ('eax', 'r8d'):
990 # Zero-extending version.
991 AddModRMCompressor(
992 '.*?' + bytes + extra_bytes +
993 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
994 '({%' + rm + '}).*{RR_NOTES}()',
995 (XX_byte_mark, '[%{}..%{} or memory]'.format(start_rm, end_rm), ''),
996 (XX_byte_mark, '[%{}..%{}]'.format(start_rm, end_rm), ''),
997 (XX_byte_mark, '[memory]', ''),
998 reg=None, rm=rm, opcode_bits=opcode_bits, register_write='sandbox')
999 # Still more forms for 64 bit case (reg to rm).
1000 if options.bitness == 64 and rm in ('al', 'spl', 'ax', 'eax', 'rax',
1001 'r8b', 'r8w', 'r8d', 'r8'):
1002 # Dangerous instructions.
1003 AddModRMCompressor(
1004 '.*?' + bytes + extra_bytes +
1005 ' (?:lock )?\\w* (?:\\$0x0,|%cl,)?'
1006 '({%' + rm + '}).*{RR_NOTES}()',
1007 (XX_byte_mark, '[%{}..%{} or memory]'.format(start_rm, end_rm), ''),
1008 (XX_byte_mark, '[%{}..%{}]'.format(start_rm, end_rm), ''),
1009 (XX_byte_mark, '[memory]', ''),
1010 reg=None, rm=rm, opcode_bits=opcode_bits, register_write='protect')
1011
1012 # Even smaller compressors: only low 3 bits of opcode are used.
1013 for reg in register_kinds + ('st(0)',):
1014 start_reg = REGISTERS[reg][0]
1015 end_reg = REGISTERS[reg][-1 if reg[0:2] != 'r8' else -2]
1016 for opcode in xrange(8):
1017 for extra_bytes in ('', ' 00', ' 00 00', ' 00 00 00 00'):
1018 for text1, text2, nibble in (
1019 ('[0..7]', '[8..f]', xrange(8)),
1020 ('[012367]', '[89abef]', (0, 1, 2, 3, 6, 7)),
1021 ('[0..6]', '[8..e]', xrange(7))
1022 ):
1023 # Operand is encoded in opcode
1024 extra_compressors.append(Compressor(
1025 '.*?[0-9a-fA-F]([0-7])' + extra_bytes +
1026 ' \\w* (?:\\$0x0,|%ax,|%st,)?'
1027 '(%(?:' + '|'.join(REGISTERS_RE[reg]) + ')).*()',
1028 (text1, '[%{}..%{}]'.format(start_reg, end_reg), ''),
1029 tuple(('{:x}'.format(n), '%' + REGISTERS[reg][n])
1030 for n in nibble)))
1031 extra_compressors.append(Compressor(
1032 '.*?[0-9a-fA-F]([89a-fA-F])' + extra_bytes +
1033 ' \\w* (?:\\$0x0,|%ax,|%st,)?'
1034 '(%(?:' + '|'.join(REGISTERS_RE[reg]) + ')).*()',
1035 (text2, '[%{}..%{}]'.format(start_reg, end_reg), ''),
1036 tuple(('{:x}'.format(n + 8), '%' + REGISTERS[reg][n])
1037 for n in nibble)))
1038 # Another version for 64 bit case
1039 if options.bitness == 64 and reg in ('eax', 'r8d'):
1040 # Operand is encoded in opcode and output
1041 extra_compressors.append(Compressor(
1042 '.*?[0-9a-fA-F]([0-7])' + extra_bytes +
1043 ' \\w* (?:\\$0x0,|%ax,|%st,)?'
1044 '(%(?:' + '|'.join(REGISTERS_RE[reg]) + ')).*'
1045 'output_rr=(%(?:'+ '|'.join(REGISTERS_RE[reg]) + ')).*()',
1046 tuple([text1] + ['[%{}..%{}]'.format(start_reg, end_reg)] * 2 +
1047 ['']),
1048 tuple(['{:x}'.format(n)] + ['%' + REGISTERS[reg][n]] * 2
1049 for n in nibble)))
1050 extra_compressors.append(Compressor(
1051 '.*?[0-9a-fA-F]([89a-fA-F])' + extra_bytes +
1052 ' \\w* (?:\\$0x0,|%ax,|%st,)?'
1053 '(%(?:' + '|'.join(REGISTERS_RE[reg]) + ')).*'
1054 'output_rr=(%(?:'+ '|'.join(REGISTERS_RE[reg]) + ')).*()',
1055 tuple([text2] + ['[%{}..%{}]'.format(start_reg, end_reg)] * 2 +
1056 ['']),
1057 tuple(['{:x}'.format(n + 8)] + ['%' + REGISTERS[reg][n]] * 2
1058 for n in nibble)))
1059 compressors = (main_compressors + memory_compressors + register_compressors +
1060 extra_compressors)
1061
1062 # Special compressors: will handle some cosmetic issues.
1063 #
1064 # SETxx ignores reg field and thus are described as many separate instructions
1065 compressors.append(Compressor(
1066 '.*0f 9[0-9a-fA-F] XX(/[0-7]) set.*()', ('', ''),
1067 [('/' + str(i), ) for i in range(8)]))
1068 # BSWAP is described with opcode "0f c8+r", not "0f /1" in manual
1069 if options.bitness == 32:
1070 compressors.append(Compressor(
1071 '.*(XX/1) bswap.*ax.*()', ('c[8..f]', ''), [('XX/1', )]))
1072 else:
1073 compressors.append(Compressor(
1074 '.*(XX/1) bswap.*ax.*()', ('c[89abef]', ''), [('XX/1', )]))
1075 compressors.append(Compressor(
1076 '.*(XX/1) bswap.*r8.*()', ('c[8..e]', ''), [('XX/1', )]))
1077 # Add mark '# write to both' to certain versions of CMPXCHG, XADD, and XCHG
1078 if options.bitness == 64:
1079 compressors.append(Compressor(
1080 '.* (?:cmpxchg|xadd|xchg).*%al\\.\\.%bh[^#]*()$',
1081 (' # write to both', ), ((), )))
1082 # "and $0xe0,[%eax..%edi]" is treated specially which means that we list all
1083 # versions of and "[$0x1..$0xff],[%eax..%edi]" separately here.
1084 # Without this rule these ands comprise 2/3 of the whole output!
1085 if options.bitness == 32:
1086 compressors.append(Compressor(
1087 '.*83 (e0 01 and \\$0x1,%eax)()',
1088 ('XX/4 00 and[l]? $0x0,[%eax..%edi or memory]', ' # special and'),
1089 [('e{} {:02x} and $0x{:x},%{}'.format(r, i, i, REGISTERS['eax'][r]), )
1090 for i in range(0x01, 0x100) for r in range(8)] +
1091 [('XX/4 00 and[l]? $0x0,[%eax..%edi or memory]', )]))
1092 else:
1093 for reg in ('eax', 'r8d'):
1094 start_reg = REGISTERS[reg][0]
1095 end_reg = REGISTERS[reg][-1 if reg[0:2] != 'r8' else -2]
1096 for index_reg in ('eax', 'r8d'):
1097 start_index = REGISTERS[index_reg][0]
1098 end_index = REGISTERS[index_reg][-1]
1099 compressors.append(Compressor(
1100 '.*83 (e0 01 and \\$0x1,%' + reg + ').*'
1101 'input_rr=(any_nonspecial); output_rr=(%' + reg + ')()',
1102 ('XX/4 00 and[l]? $0x0,[%{}..%{} or memory]'.format(start_reg,
1103 end_reg), '[%{}..%{}]'.format(start_index, end_index),
1104 '[%{}..%{}]'.format(start_reg, end_reg),
1105 ' # special and'),
1106 [('e{} {:02x} and $0x{:x},%{}'.format(r, i, i, REGISTERS[reg][r]),
1107 'any_nonspecial', '%' + REGISTERS[reg][r])
1108 for i in range(0x01, 0x100) for r in range(7 + (reg == 'eax'))] +
1109 [('XX/4 00 and[l]? $0x0,[%{}..%{} or memory]'.format(start_reg,
1110 end_reg), '[%{}..%{}]'.format(start_index, end_index),
1111 '[%{}..%{}]'.format(start_reg, end_reg))]))
1112
1113 # "and $e0" and similar are used to align %rsp. All negative values are
1114 # accepted by validator and there are 127 of these.
1115 # Consolidate them into one line.
1116 if options.bitness == 64:
1117 compressors.append(Compressor(
1118 '.*(?:81|83) (?:e4|e5) (80) (?:00 00 00 |) and \\$0x(80),%r[bs]p.*()',
1119 ('[80..ff]', '[80..ff]', ' # alignment and'),
1120 [('{:02x}'.format(i), '{:02x}'.format(i)) for i in range(0x80, 0x100)]))
1121
1122 # Merge memory and non-memory access
1123 if options.bitness == 32:
1124 letters_and_registers = (('b', 'al', ''), ('w', 'ax', ''), ('l', 'eax', ''))
1125 else:
1126 letters_and_registers = (
1127 ('b', 'al', 'eax'), ('b', 'spl', 'eax'), ('b', 'r8b', 'r8d'),
1128 ('w', 'ax', 'eax'), ('w', 'r8w', 'r8d'),
1129 ('l', 'eax', 'eax'), ('l', 'r8d', 'r8d'),
1130 ('q', 'rax', 'eax'), ('q', 'r8', 'r8d')
1131 )
1132 for letter, reg, out_reg in letters_and_registers:
1133 start_reg = REGISTERS[reg][0]
1134 end_reg = REGISTERS[reg][-1 if reg[0:2] != 'r8' else -2]
1135 all_regs = '[%{}..%{}]'.format(start_reg, end_reg)
1136 regs_mark = '[%{}..%{} or memory]'.format(start_reg, end_reg)
1137 if options.bitness == 64:
1138 start_out = REGISTERS[out_reg][0]
1139 end_out = REGISTERS[out_reg][-1 if out_reg[0:2] != 'r8' else -2]
1140 out_regs = '[%{}..%{}]'.format(start_out, end_out)
1141 for notes in ('', ' # rm to reg', ' # reg to rm'):
1142 compressors.append(Compressor(
1143 '.* \\w*(' + letter + ') .*(\\[memory]).*()()',
1144 ('[{}]?'.format(letter), regs_mark, '', ''),
1145 ((letter, '[memory]', ''), ('', all_regs, notes))))
1146 if options.bitness == 64:
1147 for index_reg in ('eax', 'r8d'):
1148 start_index = REGISTERS[index_reg][0]
1149 end_index = REGISTERS[index_reg][-1]
1150 index_regs = '[%{}..%{}]'.format(start_index, end_index)
1151 for output_rrs in ((None, out_regs), (out_regs, None), (None, None)):
1152 compressors.append(Compressor(
1153 '.* \\w*(' + letter + ') .*(\\[memory]).*; '
1154 'input_rr=(\\[%[a-z0-9]*..%[a-z0-9]*\\]); '
1155 'output_rr=(\\[%[a-z0-9]*..%[a-z0-9]*\\]|None)()()',
1156 ('[{}]?'.format(letter), regs_mark, index_regs,
1157 output_rrs[0] if output_rrs[0] is not None else output_rrs[1],
1158 '', ''),
1159 ((letter, '[memory]', index_regs, output_rrs[0], ''),
1160 ('', all_regs, 'any_nonspecial', output_rrs[1], notes))))
1161
1162 # REX compressors
1163 if options.bitness == 64:
1164 # First pretty complex set of compressors to combine versions of REX with
1165 # three lowest bits in different states.
1166 register_kind_pairs = (
1167 ( None, None),
1168 ( 'al', 'al'), ( 'al', None), (None, 'al'),
1169 ( 'ax', 'al'), ( 'al', 'ax'),
1170 ( 'ax', 'ax'), ( 'ax', None), (None, 'ax'),
1171 ( 'eax', 'al'), ( 'al', 'eax'),
1172 ( 'eax', 'ax'), ( 'ax', 'eax'),
1173 ( 'eax', 'eax'), ( 'eax', None), (None, 'eax'),
1174 ( 'rax', 'al'), ( 'al', 'rax'),
1175 ( 'rax', 'ax'), ( 'ax', 'rax'),
1176 ( 'rax', 'eax'), ( 'eax', 'rax'),
1177 ( 'rax', 'rax'), ( 'rax', None), (None, 'rax'),
1178 ( 'eax', 'mm0'), ( 'mm0', 'eax'),
1179 ( 'rax', 'mm0'), ( 'mm0', 'rax'),
1180 ( 'mm0', 'eax'), ( 'eax', 'mm0'),
1181 ( 'mm0', 'rax'), ( 'rax', 'mm0'),
1182 ( 'eax', 'xmm0'),
1183 ( 'rax', 'xmm0'),
1184 ('xmm0', 'eax'),
1185 ('xmm0', 'rax'),
1186 ( 'mm0', 'mm0'), ( 'mm0', None), (None, 'mm0'),
1187 ( 'mm0', 'xmm0'),
1188 ('xmm0', 'mm0'),
1189 ('xmm0', 'xmm0'),
1190 ('xmm0', 'ymm0'), ('xmm0', None), (None, 'xmm0'),
1191 ('ymm0', 'xmm0'),
1192 ('ymm0', 'ymm0'), ('ymm0', None), (None, 'ymm0'),
1193 )
1194 r8 = {
1195 'al': 'r8b',
1196 'ax': 'r8w',
1197 'eax': 'r8d',
1198 'rax': 'r8',
1199 'mm0': 'mmalt',
1200 'xmm0': 'xmm8',
1201 'ymm0': 'ymm8'
1202 }
1203 for reg, rm in register_kind_pairs:
1204 for last_reg, last_rm in ((-1, -1), (-1, -2), (-2, -1), (-2, -2)):
1205 if reg:
1206 start_reg = REGISTERS[reg][0]
1207 start_reg8 = REGISTERS[r8[reg]][0]
1208 end_reg = REGISTERS[reg][-1]
1209 end_reg0 = 'dil' if reg == 'al' else end_reg
1210 end_reg8 = REGISTERS[r8[reg]][last_reg]
1211 reg_regex = '\\[(%' + start_reg + '\\.\\.%' + end_reg + ')]'
1212 reg_regex0 = '\\[(%' + start_reg + '\\.\\.%' + end_reg0 + ')]'
1213 elif last_reg == -2:
1214 continue
1215 if rm:
1216 start_rm = REGISTERS[rm][0]
1217 start_rm8 = REGISTERS[r8[rm]][0]
1218 end_rm = REGISTERS[rm][-1]
1219 end_rm0 = 'dil' if rm == 'al' else end_rm
1220 end_rm8 = REGISTERS[r8[rm]][last_rm]
1221 rm_regex = ('\\[(%' + start_rm + '\\.\\.%' + end_rm + ')'
1222 '(?: or memory)?]')
1223 rm_regex0 = ('\\[(%' + start_rm + '\\.\\.%' + end_rm0 + ')'
1224 '(?: or memory)?]')
1225 elif last_rm == -2:
1226 continue
1227 for rexw in (True, False):
1228 for input_rr in (True, False):
1229 for output_rr in (True, False) if reg or rm else (None, ):
1230 for rm_to_reg in (True, False) if reg and rm else (None, ):
1231 # Legacy prefixes
1232 regex = '.*:(?: 26| 2e| 36| 3e| 64| 65| 66| 67| f0| f2| f3)*'
1233 # REX
1234 regex += '( 48).*' if rexw else '( 40|).*'
1235 # Replacement text
1236 replacement_tuple = (
1237 ' [REX:48..4f]' if rexw else ' [REX:40..47]?', )
1238 if reg:
1239 replacement_regs = '%{}..%{}'.format(start_reg, end_reg8)
1240 if rm:
1241 replacement_rms = '%{}..%{}'.format(start_rm, end_rm8)
1242 # Instruction arguments
1243 if not reg and not rm:
1244 pass
1245 elif not reg and rm:
1246 if rexw:
1247 regex += rm_regex0 + '.*'
1248 else:
1249 regex += rm_regex + '.*'
1250 replacement_tuple += (replacement_rms, )
1251 elif reg and not rm:
1252 if rexw:
1253 regex += reg_regex0 + '.*'
1254 else:
1255 regex += reg_regex + '.*'
1256 replacement_tuple += (replacement_regs, )
1257 elif rm_to_reg:
1258 if rexw:
1259 regex += rm_regex0 + ',' + reg_regex0 + '.*'
1260 else:
1261 regex += rm_regex + ',' + reg_regex + '.*'
1262 replacement_tuple += (replacement_rms, replacement_regs)
1263 else:
1264 if rexw:
1265 regex += reg_regex0 + ',' + rm_regex0 + '.*'
1266 else:
1267 regex += reg_regex + ',' + rm_regex + '.*'
1268 replacement_tuple += (replacement_regs, replacement_rms)
1269 # Input and output restricted registers
1270 if input_rr:
1271 regex += 'input_rr=\\[(%eax\\.\\.%edi)].*'
1272 replacement_tuple += ('%eax..%r15d', )
1273 if output_rr:
1274 regex += 'output_rr=\\[(%eax\\.\\.%edi)].*'
1275 replacement_tuple += ('%eax..%r14d', )
1276 regex += '()'
1277 replacement_tuple += ('', )
1278 # Replacement cases
1279 replacement_tuples = ()
1280 for byte in (range(0x48, 0x50)
1281 if rexw
1282 else range(0x40, 0x48) + ['']):
1283 replacement_case = (
1284 ' {:02x}'.format(byte) if byte else byte, )
1285 if byte:
1286 if rm:
1287 if byte & 0x1:
1288 replacement_rms = '%{}..%{}'.format(start_rm8, end_rm8)
1289 else:
1290 replacement_rms = '%{}..%{}'.format(start_rm, end_rm0)
1291 if byte & 0x2:
1292 replacement_index = '%r8d..%r15d'
1293 else:
1294 replacement_index = '%eax..%edi'
1295 if reg:
1296 if byte & 0x4:
1297 replacement_regs = '%{}..%{}'.format(start_reg8,
1298 end_reg8)
1299 else:
1300 replacement_regs = '%{}..%{}'.format(start_reg,
1301 end_reg0)
1302 else:
1303 if rm:
1304 replacement_rms = '%{}..%{}'.format(start_rm, end_rm)
1305 replacement_index = '%eax..%edi'
1306 if reg:
1307 replacement_regs = '%{}..%{}'.format(start_reg, end_reg)
1308 if not reg and not rm:
1309 pass
1310 elif not reg and rm:
1311 replacement_case += (replacement_rms, )
1312 if byte:
1313 final_rr = '%r8d..%r14d' if byte & 0x1 else '%eax..%edi'
1314 else:
1315 final_rr = '%eax..%edi'
1316 elif reg and not rm:
1317 replacement_case += (replacement_regs, )
1318 if byte:
1319 final_rr = '%r8d..%r14d' if byte & 0x4 else '%eax..%edi'
1320 else:
1321 final_rr = '%eax..%edi'
1322 elif rm_to_reg:
1323 replacement_case += (replacement_rms, replacement_regs)
1324 if byte:
1325 final_rr = '%r8d..%r14d' if byte & 0x4 else '%eax..%edi'
1326 else:
1327 final_rr = '%eax..%edi'
1328 else:
1329 replacement_case += (replacement_regs, replacement_rms)
1330 if byte:
1331 final_rr = '%r8d..%r14d' if byte & 0x1 else '%eax..%edi'
1332 else:
1333 final_rr = '%eax..%edi'
1334 if input_rr: replacement_case += (replacement_index, )
1335 if output_rr: replacement_case += (final_rr, )
1336 replacement_tuples += (replacement_case, )
1337 compressors.append(Compressor(
1338 regex, replacement_tuple, replacement_tuples))
1339 # This is pretty simple compressor to combine two lines with different REX.W
1340 # bits (only if they are otherwise identical).
1341 compressors.append(Compressor(
1342 '.*(\\[REX:40\\.\\.47]\\?).*()', ('[REX:40..4f]?', ''),
1343 (('[REX:40..47]?', ), ('[REX:48..4f]', ))))
1344
1345
1346 def ShowProgress(rule, instruction):
1347 if rule not in ShowProgress.rules_shown:
1348 first_print = True
1349 ShowProgress.rules_shown[rule]=len(ShowProgress.rules_shown)
1350 else:
1351 first_print = False
1352 print >> sys.stderr, '-------- Compressed --------'
1353 print >> sys.stderr, 'Rule:', ShowProgress.rules_shown[rule]
1354 print >> sys.stderr, '--------'
1355 compressor = compressors[rule]
1356 match = compressor.regex.match(instruction)
1357 assert match
1358 format_str = CompressionTemplate(instruction, match, '{{{}}}')
1359 replacements = sorted(format_str.format(*replacement)
1360 for replacement in compressor.replacements)
1361 if len(compressor.replacements) <= 4 or first_print:
1362 for replacement in replacements:
1363 print >> sys.stderr, replacement
1364 else:
1365 print >> sys.stderr, replacements[0]
1366 print >> sys.stderr, "..."
1367 print >> sys.stderr, replacements[-1]
1368 print >> sys.stderr, '--------'
1369 print >> sys.stderr, 'Compressed', (
1370 format_str + '{{{}}}').format(*compressor.subst)
1371 ShowProgress.rules_shown = {}
1372
1373
1374 def main():
1375 # We are keeping these global to share state graph and compressors
1376 # between workers spawned by multiprocess. Passing them every time is slow.
1377 global options, xml_file
1378 global dfa
1379 global worker_validator
1380 options, xml_file = ParseOptions()
1381 dfa = dfa_parser.ParseXml(xml_file)
1382 worker_validator = validator.Validator(
1383 validator_dll=options.validator_dll,
1384 decoder_dll=options.decoder_dll)
1385 PrepareCompressors()
1386
1387 assert dfa.initial_state.is_accepting
1388 assert not dfa.initial_state.any_byte
1389
1390 print >> sys.stderr, len(dfa.states), 'states'
1391
1392 num_suffixes = dfa_traversal.GetNumSuffixes(dfa.initial_state)
1393
1394 # We can't just write 'num_suffixes[dfa.initial_state]' because
1395 # initial state is accepting.
1396 total_instructions = sum(
1397 num_suffixes[t.to_state]
1398 for t in dfa.initial_state.forward_transitions.values())
1399 print >> sys.stderr, total_instructions, 'regular instructions total'
1400
1401 tasks = dfa_traversal.CreateTraversalTasks(dfa.states, dfa.initial_state)
1402 print >> sys.stderr, len(tasks), 'tasks'
1403
1404 pool = multiprocessing.Pool()
1405
1406 results = pool.imap(Worker, tasks)
1407
1408 total = 0
1409 num_valid = 0
1410 full_output = set()
1411 for prefix, count, valid_count, output, trace in results:
1412 print >> sys.stderr, 'Prefix:', ', '.join(map(hex, prefix))
1413 total += count
1414 num_valid += valid_count
1415 full_output |= output
1416 for rule, instruction in trace:
1417 ShowProgress(rule, instruction)
1418 for instruction in sorted(Compressed(full_output,
1419 compressors,
1420 ShowProgress)):
1421 print instruction
1422
1423 print >> sys.stderr, total, 'instructions were processed'
1424 print >> sys.stderr, num_valid, 'valid instructions'
1425
1426
1427 if __name__ == '__main__':
1428 main()
OLDNEW
« no previous file with comments | « no previous file | src/trusted/validator_ragel/testdata/32bit_regular.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698