| Index: src/trusted/validator_x86/testscripts/compare_validators.py
|
| diff --git a/src/trusted/validator_x86/testscripts/compare_validators.py b/src/trusted/validator_x86/testscripts/compare_validators.py
|
| deleted file mode 100755
|
| index ebb7d4ead47c5aa4cb7eb136d3034a5f0c84c901..0000000000000000000000000000000000000000
|
| --- a/src/trusted/validator_x86/testscripts/compare_validators.py
|
| +++ /dev/null
|
| @@ -1,274 +0,0 @@
|
| -#!/usr/bin/python
|
| -# Copyright (c) 2012 The Native Client Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -import collections
|
| -import glob
|
| -import optparse
|
| -import re
|
| -import subprocess
|
| -import sys
|
| -
|
| -import test_format
|
| -
|
| -
|
| -NCVAL_VERDICT = {
|
| - '*** <input> is safe ***': True,
|
| - '*** <input> IS UNSAFE ***': False}
|
| -
|
| -
|
| -ValidatorResult = collections.namedtuple('ValidatorResult', 'verdict offsets')
|
| -
|
| -
|
| -def ParseNval(nval_content):
|
| - """Parse content of @nval section.
|
| -
|
| - Args:
|
| - nval_content: Content of @nval section (as produced by 32-bit ncval
|
| - with options --max_errors=-1 --detailed=false --cpuid-all).
|
| -
|
| - Returns:
|
| - ValidatorResult
|
| - """
|
| -
|
| - lines = nval_content.split('\n')
|
| - last_line = lines.pop()
|
| - assert last_line == ''
|
| - verdict = NCVAL_VERDICT[lines.pop()]
|
| -
|
| - offsets = set()
|
| - for line in lines:
|
| - if re.match(r'.+ > .+ \(read overflow of .+ bytes\)', line):
|
| - # Add to offsets something that designedly can't occur in offsets
|
| - # produced by ParseRdfaOutput, so that difference will show up and
|
| - # corresponding test won't be missed.
|
| - offsets.add('read overflow')
|
| - continue
|
| - if line == 'ErrorSegmentation':
|
| - # Same here.
|
| - offsets.add('ErrorSegmentation')
|
| - continue
|
| -
|
| - # Parse error message of the form
|
| - # VALIDATOR: 4: Bad prefix usage
|
| - m = re.match(r'VALIDATOR: ([0-9a-f]+): (.*)$', line, re.IGNORECASE)
|
| -
|
| - assert m is not None, "can't parse %r" % line
|
| -
|
| - offset = int(m.group(1), 16)
|
| - offsets.add(offset)
|
| -
|
| - return ValidatorResult(verdict=verdict, offsets=offsets)
|
| -
|
| -
|
| -def ParseRval(rval_content):
|
| - """Parse content of @rval section.
|
| -
|
| - Args:
|
| - nval_content: Content of @rval section (as produced by 64-bit ncval
|
| - with options --max_errors=-1 --readwrite_sfi --detailed=false
|
| - --annotate=false --cpuid-all).
|
| -
|
| - Returns:
|
| - ValidatorResult
|
| - """
|
| -
|
| - lines = rval_content.split('\n')
|
| - last_line = lines.pop()
|
| - assert last_line == ''
|
| - verdict = NCVAL_VERDICT[lines.pop()]
|
| -
|
| - offsets = set()
|
| - for prev_line, line in zip([None] + lines, lines):
|
| - if line.startswith('VALIDATOR: Checking jump targets:'):
|
| - continue
|
| - if line.startswith('VALIDATOR: Checking that basic blocks are aligned'):
|
| - continue
|
| -
|
| - # Skip disassembler output of the form
|
| - # VALIDATOR: 0000000000000003: 49 89 14 07 mov [%r15+%rax*1], %rdx
|
| - m = re.match(r'VALIDATOR: ([0-9a-f]+):', line, re.IGNORECASE)
|
| - if m is not None:
|
| - continue
|
| -
|
| - # Parse error message of the form
|
| - # VALIDATOR: ERROR: 20: Bad basic block alignment.
|
| - m = re.match(r'VALIDATOR: ERROR: ([0-9a-f]+): (.*)', line, re.IGNORECASE)
|
| - if m is not None:
|
| - offset = int(m.group(1), 16)
|
| - offsets.add(offset)
|
| - continue
|
| -
|
| - # Parse two-line error messages of the form
|
| - # VALIDATOR: 0000000000000003: 49 89 14 07 mov [%r15+%rax*1], %rdx
|
| - # VALIDATOR: ERROR: Invalid index register in memory offset
|
| - m = re.match(r'VALIDATOR: (ERROR|WARNING): .*$', line, re.IGNORECASE)
|
| - if m is not None:
|
| - message_type = m.group(1)
|
| - assert prev_line is not None, (
|
| - "can't deduce error offset because line %r "
|
| - "is not preceded with disassembly" % line)
|
| - m2 = re.match(r'VALIDATOR: ([0-9a-f]+):', prev_line, re.IGNORECASE)
|
| - assert m2 is not None, "can't parse line %r preceding line %r" % (
|
| - prev_line,
|
| - line)
|
| - offset = int(m2.group(1), 16)
|
| - if message_type != 'WARNING':
|
| - offsets.add(offset)
|
| - continue
|
| -
|
| - raise AssertionError("can't parse line %r" % line)
|
| -
|
| - return ValidatorResult(verdict=verdict, offsets=offsets)
|
| -
|
| -
|
| -RDFA_VERDICT = {
|
| - 'return code: 0': True,
|
| - 'return code: 1': False}
|
| -
|
| -
|
| -def ParseRdfaOutput(rdfa_content):
|
| - """Parse content of @rdfa_output section.
|
| -
|
| - Args:
|
| - rdfa_content: Content of @rdfa_output section in .test file.
|
| -
|
| - Returns:
|
| - ValidatorResult
|
| - """
|
| -
|
| - lines = rdfa_content.split('\n')
|
| - assert lines[-1] == ''
|
| - verdict = RDFA_VERDICT[lines[-2]]
|
| -
|
| - offsets = set()
|
| - for line in lines[:-2]:
|
| - # Parse error message of the form
|
| - # 4: [1] DFA error in validator
|
| - m = re.match(r'([0-9a-f]+): \[\d+\] (.*)$', line, re.IGNORECASE)
|
| - assert m is not None, "can't parse %r" % line
|
| - offset = int(m.group(1), 16)
|
| - offsets.add(offset)
|
| -
|
| - return ValidatorResult(verdict=verdict, offsets=offsets)
|
| -
|
| -
|
| -def Compare(options, items_list, stats):
|
| - val_field = {32: 'nval', 64: 'rval'}[options.bits]
|
| - val_parser = {32: ParseNval, 64: ParseRval}[options.bits]
|
| -
|
| - info = dict(items_list)
|
| - if 'rdfa_output' not in info:
|
| - if val_field in info:
|
| - print ' rdfa_output section is missing'
|
| - stats['rdfa missing'] +=1
|
| - else:
|
| - print ' both sections are missing'
|
| - stats['both missing'] += 1
|
| - return items_list
|
| - if val_field not in info:
|
| - print ' @%s section is missing' % val_field
|
| - stats['val missing'] += 1
|
| - return items_list
|
| -
|
| - val = val_parser(info[val_field])
|
| - rdfa = ParseRdfaOutput(info['rdfa_output'])
|
| -
|
| - if val == rdfa:
|
| - stats['agree'] += 1
|
| - if options.git:
|
| - # Stage the file for commit, so that files that pass can be
|
| - # committed with "git commit" (without -a or other arguments).
|
| - subprocess.check_call(['git', 'add', test_filename])
|
| -
|
| - if 'validators_disagree' in info:
|
| - stats['spurious @validators_disagree'] += 1
|
| - print (' warning: validators agree, but the section '
|
| - '"@validators_disagree" is present')
|
| - else:
|
| - stats['disagree'] += 1
|
| - if 'validators_disagree' in info:
|
| - print ' validators disagree, see @validators_disagree section'
|
| - else:
|
| - print ' validators disagree!'
|
| - stats['unexplained disagreements'] += 1
|
| -
|
| - diff = ['TODO: explain this\n']
|
| - if val.verdict != rdfa.verdict:
|
| - diff.append('old validator verdict: %s\n' % val.verdict)
|
| - diff.append('rdfa validator verdict: %s\n' % rdfa.verdict)
|
| -
|
| - set_diff = val.offsets - rdfa.offsets
|
| - if len(set_diff) > 0:
|
| - diff.append('errors reported by old validator but not by rdfa one:\n')
|
| - for offset in sorted(set_diff):
|
| - if isinstance(offset, int):
|
| - offset = hex(offset)
|
| - diff.append(' %s\n' % offset)
|
| -
|
| - set_diff = rdfa.offsets - val.offsets
|
| - if len(set_diff) > 0:
|
| - diff.append('errors reported by rdfa validator but not by old one:\n')
|
| - for offset in sorted(set_diff):
|
| - if isinstance(offset, int):
|
| - offset = hex(offset)
|
| - diff.append(' %s\n' % offset)
|
| -
|
| - items_list = items_list + [('validators_disagree', ''.join(diff))]
|
| -
|
| - return items_list
|
| -
|
| -
|
| -def main(args):
|
| - parser = optparse.OptionParser()
|
| - parser.add_option('--bits',
|
| - type=int,
|
| - help='The subarchitecture to run tests against: 32 or 64')
|
| - parser.add_option('--update',
|
| - default=False,
|
| - action='store_true',
|
| - help='When validators disagree, fill in '
|
| - '@validators_disagree section (if not present)')
|
| - # TODO(shcherbina): Get rid of this option once most tests are committed.
|
| - parser.add_option('--git',
|
| - default=False,
|
| - action='store_true',
|
| - help='Add tests with no discrepancies to git index')
|
| -
|
| - options, args = parser.parse_args(args)
|
| -
|
| - if options.bits not in [32, 64]:
|
| - parser.error('specify --bits 32 or --bits 64')
|
| -
|
| - if len(args) == 0:
|
| - parser.error('No test files specified')
|
| -
|
| - stats = collections.defaultdict(int)
|
| -
|
| - for glob_expr in args:
|
| - test_files = sorted(glob.glob(glob_expr))
|
| - if len(test_files) == 0:
|
| - raise AssertionError(
|
| - '%r matched no files, which was probably not intended' % glob_expr)
|
| - for test_file in test_files:
|
| - print 'Comparing', test_file
|
| - tests = test_format.LoadTestFile(test_file)
|
| - tests = [Compare(options, test, stats) for test in tests]
|
| - if options.update:
|
| - test_format.SaveTestFile(tests, test_file)
|
| -
|
| - print 'Stats:'
|
| - for key, value in stats.items():
|
| - print ' %s: %d' %(key, value)
|
| -
|
| - if options.update:
|
| - if stats['unexplained disagreements'] > 0:
|
| - print '@validators_disagree sections were created'
|
| - else:
|
| - if stats['unexplained disagreements'] > 0:
|
| - sys.exit(1)
|
| -
|
| -
|
| -if __name__ == '__main__':
|
| - main(sys.argv[1:])
|
|
|