# -*- python -*- # Copyright (c) 2011 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 os import sys Import('env') # # # Build x86 only pieces # # if not env.Bit('target_x86'): Return() # ------------------------------------------------------ # General adjustments to the environment for builds. # Defines which test sets tests should be added to. STANDARD_TESTS = ['small_tests', 'validator_tests'] # Define which test sets modeling test should be added to MODELING_TESTS = STANDARD_TESTS + ['validator_modeling'] # TODO(bradchen): eliminate need for the following line env.FilterOut(CCFLAGS=['-Wextra', '-Wswitch-enum', '-Wsign-compare']) # Defines this source directory. src_dir = '$MAIN_DIR/src/trusted/validator/x86/decoder/generator' # Defines the source directory for locally generated files. local_src_dir = '$MAIN_DIR/src/trusted/validator/x86/decoder/generator/gen' # Defines the source directory where validator generated files should be added. tables_src_dir = '$MAIN_DIR/src/trusted/validator/x86/decoder/gen' # Create environment for command-line tools and testing, rather than # part of the TCB. Then define compile-time flag that communicates # that we are compiling in the test environment (rather than for the TCB). test_env = env.Clone() test_env.Append(CCFLAGS=['-DNACL_TRUSTED_BUT_NOT_TCB']) # ------------------------------------------------------ # Source generation: # # Source generation is done in three steps. The first generates # enumerated types. The second generates decoder tables needed by # the decoders. In between these two steps we generate the executables # that build the decoder tables. # # Source generation is controlled by to command line directives, and can be # built in either the x86-32 or the x86-64 platform. The two directives are: # # valclean : Delete the existing versions of the generated files. # This step should be done whenever ANY change may effect # the generated sources. # # valgen : Regenerate any deleted source files. Note: some generated # source files do understand dependencies and do not need to be # deleted before calling valgen. However, do not count on this, # as some dependencies are not caught. To be safe, if you have # modified a file that effects source generation, run "valclean" # followed by a "valgen" to guarantee that generated sources are # up to date. gen_env = env.Clone() gen_env.Append(CCFLAGS=['-DNACL_TRUSTED_BUT_NOT_TCB']) generate = False if 'valgen' in COMMAND_LINE_TARGETS: generate = True if 'valclean' in COMMAND_LINE_TARGETS: generate = True # Set of generated (source) decoder tables. tables = [] # Set of generated (source) enumeration files. enum_headers = [] # ------------------------------------------------------ # Source generation step 1: Generate enumerated types. # # Only generate/clean these files if the alias is specified on the # command line. We conditionally add these pieces to scons to prevent # a normal invocation from accidentally regenerating the files. # if generate: # # valgen - Table Generator # # We create an alias 'valgen' which we use to generate the various # headers used by the x86 validator. This target will generate # *.h, *_impl.h from the *.enum files, as well as the executables # ncdecode_table and ncdecode_tablegen which are used to generate # the large opcode tables. # # Get the directory in which we will generate checking in files. header_prefix = gen_env.subst('${MAIN_DIR}') if header_prefix.endswith('/native_client'): header_prefix = header_prefix[0:header_prefix.rfind('native_client')] elif header_prefix.endswith('/native_client/'): header_prefix = header_prefix[0:header_prefix.rfind('native_client/')] #------------------------------------------------------ # Generate the needed header files for enumerated types. # Note that we use the same directory for all platforms. # Define enumerate type files, and the options to process. ncv_enum_pairs = { 'nacl_disallows': '--name=NaClDisallowsFlag --add_size=1', } # Now code generate the enumerated types. for ncv_enum in ncv_enum_pairs: ncv_options = ncv_enum_pairs[ncv_enum] ncv_enum_file = gen_env.File(ncv_enum + '.enum') ncv_header_1 = gen_env.File('%s/%s.h' % (local_src_dir, ncv_enum)) ncv_header_2 = gen_env.File('%s/%s_impl.h' % (local_src_dir, ncv_enum)) cmd_line = ( '${PYTHON} %s --header="%s" --source="%s" --path_prefix="%s" %s %s' % (gen_env.File('%s/../../../../validator_x86/enum_gen.py' % src_dir), ncv_header_1, ncv_header_2, header_prefix, ncv_options, ncv_enum_file)) gen_env.Command([ncv_header_1, ncv_header_2], ncv_enum_file, cmd_line) enum_headers.append(ncv_header_1) enum_headers.append(ncv_header_2) # ------------------------------------------------------ # Table generators: # # In the middle of generating, we unconditionally add ncdecode_table and # ncdecode_tablegen so that the tests which depend on it, can run correctly. # This step sits in the middle because of dependency order, where the next # generation step requires this executable. # Add new x86 table generator. # # ncdecode_tablegen = gen_env.ComponentProgram( 'ncdecode_tablegen', ['ncdecode_tablegen.c', 'nc_compress.c', 'ncval_simplify.c', 'ncdecode_forms.c', 'zero_extends.c', 'nc_def_jumps.c', 'long_mode.c', 'nc_rep_prefix.c', 'defsize64.c', 'nacl_illegal.c', 'lock_insts.c', 'ncdecode_st.c', 'ncdecode_onebyte.c', 'ncdecode_0F.c', 'ncdecode_sse.c', 'ncdecodeX87.c', 'nacl_regsgen.c', 'modeled_nacl_inst.c', ], EXTRA_LIBS=[gen_env.NaClTargetArchSuffix('nc_opcode_modeling_verbose'), 'utils']) # ------------------------------------------------------ # Source generation step 2: Generate decoder tables. # # Now we are back to conditionally defining the large tables generated # by ncdecode_tablegen. # if generate: # # Generate 32 and 64 bit versions of nc_opcode_table and nc_subregs # for filename in ['nc_opcode_table', 'nc_subregs', 'ncval_reg_sfi_opcode_table']: for bits in ['32', '64']: fullname = '%s/%s_%s.h' % (tables_src_dir, filename, bits) exe_path = '${STAGING_DIR}/${PROGPREFIX}ncdecode_tablegen${PROGSUFFIX}' if filename == 'nc_subregs': cmd_line = '%s -m%s -nacl_subregs %s'% (exe_path, bits, fullname) elif filename == 'ncval_reg_sfi_opcode_table': cmd_line = '%s -m%s -validator_decoder %s'% (exe_path, bits, fullname) else: cmd_line = '%s -m%s %s'% (exe_path, bits, fullname) out = gen_env.Command(env.File(fullname), exe_path, cmd_line) tables.append(fullname) # Generate 32 and 64 bit versions of ncval_opcode_table (validator # decoder tables) gen_list = enum_headers + tables gen_env.AlwaysBuild( gen_env.Alias('valgen', gen_list)) gen_env.AlwaysBuild( gen_env.Alias('valclean', action=[Delete(x) for x in gen_list])) # ====================================================================== # Helper functions for getting automated tests from the corresponding # test directory. TESTDATA_DIR = 'testdata/' TESTDATA_SUBARCH_DIR = TESTDATA_DIR + env['TARGET_SUBARCH'] + '/' # Generates the set of test files with the given extension. def __GoldenFiles(ext): return Glob(TESTDATA_SUBARCH_DIR + '*.' + ext) # Generates base names (i.e. minus path and extention (ext) suffix) of # all test data input files. def __FilterOutTestFileBaseGen(files, ext): for f in files: yield os.path.basename(f.path).replace('.' + ext, '') # Generates the set of golden bases for the given extension. def __GoldenBases(ext): return __FilterOutTestFileBaseGen(__GoldenFiles(ext), ext) # Generates the corresponding test file from the given base. def __BaseTestFile(base, ext): return test_env.File(TESTDATA_SUBARCH_DIR + base + '.' + ext) # Generates the corresponding output file from the given base. def __OutTestFile(test, base, ext): return test + '_' + base + '.' + ext + '.out' def __AddTest(test, test_env, base, ext, command, groups): test_env.AddNodeToTestSuite(command, groups, 'run_%s_%s_%s_test' % (test, base, ext)) #------------------------------------------------------------------ # Generate the header files containing the modeled x86 instructions. def TestGeneratedInstructionTables(target_subarch, golden_filename, validator_decoder, groups): test_name = 'ncdecode_tablegen_%s_%s' % (golden_filename, target_subarch) golden_output = env.File('%s/%s_%s.h' % (tables_src_dir, golden_filename, target_subarch)) cmd_line = [ncdecode_tablegen, '-m%s' % (target_subarch,)] if validator_decoder: cmd_line += ['-validator_decoder'] test = test_env.CommandTest(test_name + '.out', cmd_line, stdout_golden = golden_output) test_env.AddNodeToTestSuite(test, groups, 'run_%s_test' % test_name) def TestGeneratedSubregisterTables(target_subarch, golden_filename, groups): test_name = 'ncdecode_tablegen_subreg_tables_' + target_subarch golden_output = env.File('%s/%s_%s.h' % (tables_src_dir, golden_filename, target_subarch)) test = test_env.CommandTest( test_name + '.out', [ncdecode_tablegen, '-m%s -nacl_subregs' % (target_subarch,)], stdout_golden = golden_output) test_env.AddNodeToTestSuite(test, groups, 'run_%s_test' % test_name) # The following verifies that we generate the same source files, independent of # whether the 32 bit or 64 bit table generator is used. # Note: This is important in the 64-bit case on Windows, in that we want # to make sure if the 32-bit generator is used, we still generate the # same source files. for test_subarch in ['32', '64']: TestGeneratedInstructionTables(test_subarch, 'nc_opcode_table', False, STANDARD_TESTS) TestGeneratedInstructionTables(test_subarch, 'ncval_reg_sfi_opcode_table', True, STANDARD_TESTS) TestGeneratedSubregisterTables(test_subarch, 'nc_subregs', STANDARD_TESTS) # Run test to see if we have changed the set of modeled instructions. def __AddModeledInstsTest(): prefixes = [''] if test_env.Bit('build_x86_64'): prefixes.append('ncval_reg_sfi_') for prefix in prefixes: test = 'test' base = prefix + 'modeled_insts' ext = 'txt' command = [ncdecode_tablegen, '-m%s' % (env['TARGET_SUBARCH']), '-documentation'] if prefix == 'ncval_reg_sfi_': command.append('-validator_decoder') model = test_env.CommandTest( __OutTestFile(test, base, ext), command, stdout_golden = __BaseTestFile(base, ext)) __AddTest(test, test_env, base, ext, model, MODELING_TESTS) __AddModeledInstsTest()