| Index: src/trusted/validator/x86/testing/tf/val_runner.py
|
| diff --git a/src/trusted/validator/x86/testing/tf/val_runner.py b/src/trusted/validator/x86/testing/tf/val_runner.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d345bef0be9c9aacb4ffa55d32a3442ab1dfb176
|
| --- /dev/null
|
| +++ b/src/trusted/validator/x86/testing/tf/val_runner.py
|
| @@ -0,0 +1,174 @@
|
| +# 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 re
|
| +
|
| +import utils
|
| +
|
| +
|
| +VALIDATORS = ['nc', 'dfa']
|
| +
|
| +
|
| +ncval32 = None
|
| +ncval64 = None
|
| +rdfaval = None
|
| +
|
| +
|
| +def AddValidatorsOptions(option_parser):
|
| + option_parser.add_option('--ncval32', dest='ncval32', type='string')
|
| + option_parser.add_option('--ncval64', dest='ncval64', type='string')
|
| + option_parser.add_option('--rdfaval', dest='rdfaval', type='string')
|
| +
|
| +
|
| +def ProcessValidatorsOptions(options):
|
| + global ncval32
|
| + global ncval64
|
| + global rdfaval
|
| +
|
| + if options.ncval32 is not None:
|
| + ncval32 = options.ncval32
|
| +
|
| + if options.ncval64 is not None:
|
| + ncval64 = options.ncval64
|
| +
|
| + if options.rdfaval is not None:
|
| + rdfaval = options.rdfaval
|
| +
|
| +
|
| +def SplitToLines(content):
|
| + return [line.rstrip() for line in content.rstrip().split('\n')]
|
| +
|
| +
|
| +def RunNcVal32(hex_name):
|
| + args = [
|
| + '--hex_text=-',
|
| + '--max_errors=-1',
|
| + '--detailed=false',
|
| + '--cpuid-all'
|
| + ]
|
| +
|
| + with open(hex_name) as input:
|
| + result = utils.CheckOutput([ncval32] + args, stdin=input)
|
| +
|
| + return SplitToLines(result)
|
| +
|
| +
|
| +def RunNcVal64(hex_name):
|
| + args = [
|
| + '--hex_text=-',
|
| + '--max_errors=-1',
|
| + '--readwrite_sfi',
|
| + '--annotate=false',
|
| + '--cpuid-all',
|
| + '--detailed=false',
|
| + ]
|
| +
|
| + with open(hex_name) as input:
|
| + result = utils.CheckOutput([ncval64] + args, stdin=input)
|
| +
|
| + return SplitToLines(result)
|
| +
|
| +
|
| +def ParseNcValVerdict(last_line):
|
| + m = re.match(r'\*\*\* <input> (is safe|IS UNSAFE) \*\*\*$', last_line)
|
| + assert m is not None, 'unexpected ncval output "%s"' % last_line
|
| + return m.group(1) == 'is safe'
|
| +
|
| +
|
| +def ParseNcVal32(lines):
|
| + assert len(lines) > 0, 'ncval output is empty'
|
| +
|
| + errors = []
|
| + for line in lines[:-1]:
|
| + line = line.strip()
|
| + if line == '':
|
| + continue
|
| +
|
| + if re.match(r'.+ > .+ \(read overflow of .+ bytes\)', line):
|
| + errors.append((0, line))
|
| + continue
|
| + if line == 'ErrorSegmentation':
|
| + errors.append((0, line))
|
| + 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 '%s'" % line
|
| +
|
| + offset = int(m.group(1), 16)
|
| + message = m.group(2)
|
| + errors.append((offset, message))
|
| + safe = ParseNcValVerdict(lines[-1])
|
| + return safe, errors
|
| +
|
| +
|
| +def ParseNcVal64(lines):
|
| + assert len(lines) > 0, 'ncval output is empty'
|
| +
|
| + errors = []
|
| + for i, line in enumerate(lines[:-1]):
|
| + 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)
|
| + errors.append((offset, m.group(2)))
|
| + 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:
|
| + m2 = re.match(r'VALIDATOR: ([0-9a-f]+):', lines[i-1], re.IGNORECASE)
|
| + assert m2 is not None, "can't parse line '%s' preceding line '%s'" % (
|
| + lines[i-1],
|
| + line
|
| + )
|
| + offset = int(m2.group(1), 16)
|
| + errors.append((offset, m.group(1)))
|
| + continue
|
| +
|
| + raise AssertionError("can't parse line '%s'" % line)
|
| +
|
| + safe = ParseNcValVerdict(lines[-1])
|
| + return safe, errors
|
| +
|
| +
|
| +ValidationResults = collections.namedtuple('ValidationResults', 'safe, errors')
|
| +
|
| +
|
| +def RunValidator(validator, bits, data):
|
| + assert validator in VALIDATORS
|
| + assert bits in [32, 64]
|
| + assert len(data) % 32 == 0
|
| +
|
| + if validator == 'nc':
|
| + with utils.TempFile(mode='w') as hex_file:
|
| + hex_file.write('%s\n' % utils.DataToReadableHex(data))
|
| + hex_file.flush()
|
| +
|
| + if bits == 32:
|
| + safe, errors = ParseNcVal32(RunNcVal32(hex_file.name))
|
| + elif bits == 64:
|
| + safe, errors = ParseNcVal64(RunNcVal64(hex_file.name))
|
| +
|
| + elif validator == 'dfa':
|
| + raise NotImplementedError('Code for running rdfa is temporarily removed')
|
| +
|
| + return ValidationResults(safe=safe, errors=errors)
|
|
|