Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # -*- python -*- | 1 # -*- python -*- |
| 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 from SCons.Errors import UserError | 6 from SCons.Errors import UserError |
| 7 | 7 |
| 8 Import('env') | 8 Import('env') |
| 9 | 9 |
| 10 # | 10 # |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 | 23 |
| 24 INST_DEFS = [ | 24 INST_DEFS = [ |
| 25 'unreviewed/general_purpose_instructions.def', | 25 'unreviewed/general_purpose_instructions.def', |
| 26 'unreviewed/system_instructions.def', | 26 'unreviewed/system_instructions.def', |
| 27 'unreviewed/x87_instructions.def', | 27 'unreviewed/x87_instructions.def', |
| 28 'unreviewed/mmx_instructions.def', | 28 'unreviewed/mmx_instructions.def', |
| 29 'unreviewed/xmm_instructions.def', | 29 'unreviewed/xmm_instructions.def', |
| 30 'unreviewed/nops.def' | 30 'unreviewed/nops.def' |
| 31 ] | 31 ] |
| 32 | 32 |
| 33 | |
| 34 | |
| 35 | |
| 36 # Generate 32 and 64 bit versions of decoders and validators. Both libraries | |
| 37 # are used for command-line decoder and validator those detect specific | |
| 38 # architecture of the ELF file provided. | |
| 39 env.ComponentLibrary('dfa_validate_x86_32', | |
| 40 ['gen/validator_x86_32.c']) | |
| 41 env.ComponentLibrary('dfa_validate_x86_64', | |
| 42 ['gen/validator_x86_64.c']) | |
| 43 env.ComponentLibrary('dfa_decode_x86_32', | |
| 44 ['gen/decoder_x86_32.c']) | |
| 45 env.ComponentLibrary('dfa_decode_x86_64', | |
| 46 ['gen/decoder_x86_64.c']) | |
| 47 | |
| 48 # Glue library called from service runtime. The source file depends on the | |
| 49 # target architecture. | |
| 50 caller_lib_bits = None | |
| 51 if env.Bit('target_x86_32'): | |
| 52 caller_lib_bits = '32' | |
| 53 if env.Bit('target_x86_64'): | |
| 54 caller_lib_bits = '64' | |
| 55 if caller_lib_bits: | |
| 56 caller_lib = 'dfa_validate_caller_x86_%s' % caller_lib_bits | |
| 57 env.ComponentLibrary(caller_lib, | |
| 58 ['unreviewed/dfa_validate_%s.c' % caller_lib_bits]) | |
| 59 | |
| 60 # Command-line decoder. | |
| 61 decoder_test = env.ComponentProgram( | |
| 62 'decoder_test', | |
| 63 ['unreviewed/decoder_test.c'], | |
| 64 EXTRA_LIBS=['dfa_decode_x86_32', 'dfa_decode_x86_64']) | |
| 65 | |
| 66 # Command-line validator. | |
| 67 validator_test_exe = env.ComponentProgram( | |
| 68 'validator_test', | |
| 69 ['unreviewed/validator_test.c'], | |
| 70 EXTRA_LIBS=['dfa_validate_x86_32', 'dfa_validate_x86_64']) | |
| 71 | |
| 72 # Python-based regression test. TODO(pasko): remove it when validator_tests are | |
| 73 # migrated to be able to run with the new validator. | |
| 74 if env.Bit('validator_ragel'): | |
| 75 test_node = env.CommandTest('validator_test_py.out', | |
| 76 command=['${PYTHON}', | |
| 77 env.File('unreviewed/validator_test.py'), | |
| 78 validator_test_exe]) | |
| 79 env.AddNodeToTestSuite(test_node, ['small_tests'], 'run_validator_test_py') | |
| 80 | |
| 81 | |
| 33 # Source generation: | 82 # Source generation: |
| 34 # | 83 # |
| 35 # dfagen : Regenerate any autogenerated source files. | 84 # dfagen : Regenerate any autogenerated source files. |
| 36 | 85 |
| 37 generate = False | 86 dfa_aliases = 'dfagen', 'dfaclean', 'dfacheckdecoder' |
| 38 if 'dfagen' in COMMAND_LINE_TARGETS or 'dfaclean' in COMMAND_LINE_TARGETS: | 87 |
| 39 generate = True | 88 generate = any(a in COMMAND_LINE_TARGETS for a in dfa_aliases) |
| 40 | 89 |
| 41 if generate: | 90 if generate: |
| 42 if not env.Bit('host_linux'): | 91 if not env.Bit('host_linux'): |
| 43 raise UserError('Right now DFA generation is only supported on Linux') | 92 raise UserError('Right now DFA generation is only supported on Linux') |
| 44 | 93 |
| 45 # Source generation step 1: Build generator of ragel files. | 94 # Source generation step 1: Build generator of ragel files. |
| 46 # | 95 # |
| 47 # We have generator which reads .def files and produced automaton definition. | 96 # We have generator which reads .def files and produced automaton definition. |
| 48 # | 97 # |
| 49 # Ragel is included in most Linux distributions, but it's not standard tool | 98 # Ragel is included in most Linux distributions, but it's not standard tool |
| 50 # on MacOS/Windows thus we only support gneration of automata under Linux. | 99 # on MacOS/Windows thus we only support gneration of automata under Linux. |
| 51 # This also means that we don't need to make sure gen_dfa.cc is portable to | 100 # This also means that we don't need to make sure gen_dfa.cc is portable to |
| 52 # non-POSIX platforms (in particular it's not Windows compatible). | 101 # non-POSIX platforms (in particular it's not Windows compatible). |
| 53 | 102 |
| 54 env_gen_dfa = env.Clone() | 103 env_gen_dfa = env.Clone() |
| 55 env_gen_dfa.Append(CCFLAGS=['-std=c++0x', '-DNACL_TRUSTED_BUT_NOT_TCB']) | 104 env_gen_dfa.Append(CCFLAGS=['-std=c++0x', '-DNACL_TRUSTED_BUT_NOT_TCB']) |
| 56 | 105 |
| 57 gen_dfa = env_gen_dfa.ComponentProgram( | 106 gen_dfa = env_gen_dfa.ComponentProgram( |
| 58 'gen_dfa', | 107 'gen_dfa', |
| 59 ['unreviewed/gen_dfa.cc']) | 108 ['unreviewed/gen_dfa.cc']) |
| 60 | 109 |
| 61 # Source generation step 2: Generate decoder automatas. | 110 # Source generation step 2: Generate decoder automata. |
| 62 # | 111 # |
| 63 # Now we are back to conditionally defining the large automata generated | 112 # Now we are back to conditionally defining the large automata generated |
| 64 # by gen_dfa. | 113 # by gen_dfa. |
| 65 | 114 |
| 66 def MakeAutomaton(bits, automaton, dfa_gen_actions, ragel_flags): | 115 def MakeAutomaton(bits, automaton, dfa_gen_actions, ragel_flags): |
| 67 rl_file = '%s_x86_%s_instruction.rl' % (automaton, bits) | 116 rl_file = '%s_x86_%s_instruction.rl' % (automaton, bits) |
| 68 | 117 |
| 69 # We are cheating here: there are two autogenerated files: | 118 # We are cheating here: there are two autogenerated files: |
| 70 # .rl and _consts.c, but we only track .rl one. This is safe because | 119 # .rl and _consts.c, but we only track .rl one. This is safe because |
| 71 # _consts.c file includes constants referenced by .rl file and if .rl | 120 # _consts.c file includes constants referenced by .rl file and if .rl |
| 72 # file is not changed _consts.c is guaranteed to be the same (reverse | 121 # file is not changed _consts.c is guaranteed to be the same (reverse |
| 73 # is not true). | 122 # is not true). |
| 123 | |
| 74 const_file = '%s/%s_x86_%s_instruction_consts.c' % ( | 124 const_file = '%s/%s_x86_%s_instruction_consts.c' % ( |
| 75 val_src_dir, automaton, bits) | 125 val_src_dir, automaton, bits) |
| 76 | 126 |
| 77 exe_path = '${STAGING_DIR}/${PROGPREFIX}gen_dfa${PROGSUFFIX}' | |
| 78 env.Command( | 127 env.Command( |
| 79 target=rl_file, | 128 target=rl_file, |
| 80 source=[exe_path] + INST_DEFS, | 129 source=[gen_dfa] + INST_DEFS, |
| 81 action=( | 130 action=( |
| 82 '${SOURCES[0]} -o ${TARGET} -c %s -m %s -d %s %s') % ( | 131 '${SOURCES[0]} -o ${TARGET} -c %s -m %s -d %s %s') % ( |
| 83 # Const file (-c): not tracked by SCONS (see above) | 132 # Const file (-c): not tracked by SCONS (see above) |
| 84 const_file, | 133 const_file, |
| 85 # Argument for CPU type (-m): either "ia32" or "amd64". | 134 # Argument for CPU type (-m): either "ia32" or "amd64". |
| 86 {'32': 'ia32', '64': 'amd64'}[bits], | 135 {'32': 'ia32', '64': 'amd64'}[bits], |
| 87 # (-d): | 136 # (-d): |
| 88 dfa_gen_actions, | 137 dfa_gen_actions, |
| 89 # pass inst defs as remaining parameters | 138 # pass inst defs as remaining parameters |
| 90 ' '.join('${SOURCES[%d]}' % (i+1) | 139 ' '.join('${SOURCES[%d]}' % (i+1) |
| 91 for i in range(len(INST_DEFS))) | 140 for i in range(len(INST_DEFS))) |
| 92 ) | 141 ) |
| 93 ) | 142 ) |
| 94 c_file = '%s_x86_%s.c' % (automaton, bits) | 143 c_file = '%s_x86_%s.c' % (automaton, bits) |
| 95 c_full_filename = '%s/%s' % (val_src_dir, c_file) | 144 c_full_filename = '%s/%s' % (val_src_dir, c_file) |
| 96 env.Command( | 145 env.Command( |
| 97 target=c_file, | 146 target=c_file, |
| 98 source=['unreviewed/%s_x86_%s.rl' % (automaton, bits), rl_file], | 147 source=['unreviewed/%s_x86_%s.rl' % (automaton, bits), rl_file], |
| 99 action=['%s %s -LL -I%s ${SOURCES[0]} -o ${TARGET}' % ( | 148 action=['%s %s -LL -I%s ${SOURCES[0]} -o ${TARGET}' % ( |
| 100 ragel_binary, ragel_flags, rl_src_dir)] | 149 ragel_binary, ragel_flags, rl_src_dir)] |
| 101 ) | 150 ) |
| 102 | 151 |
| 103 def InjectGeneratedFileHeader(target, source, env): | 152 def InjectGeneratedFileHeader(target, source, env): |
| 104 source_filename = source[0].get_abspath() | 153 source_filename = source[0].get_abspath() |
| 105 target_filename = target[0].get_abspath() | 154 target_filename = target[0].get_abspath() |
| 106 architecture = {'x86_32': 'ia32', | 155 architecture = {'x86_32': 'ia32', |
| 107 'x86_64': 'x86-64'}[target_filename[-8:-2]] | 156 'x86_64': 'x86-64'}[target_filename[-8:-2]] |
| 157 | |
| 108 with open(source_filename, 'r') as source_file: | 158 with open(source_filename, 'r') as source_file: |
| 109 with open(target_filename, 'w') as target_file: | 159 comment, sep, rest = source_file.read().partition('*/') |
| 110 target_file.write( | 160 if sep == '': |
| 111 """/* native_client/%s | 161 raise UserError('Generated file %s does not have ' |
| 112 * THIS FILE IS AUTO-GENERATED. DO NOT EDIT. | 162 'header comment block' % source_filename) |
| 113 * Compiled for %s mode. | |
| 114 */""" % (target_filename, architecture)) | |
| 115 | 163 |
| 116 comment, sep, rest = source_file.read().partition('*/') | 164 with open(target_filename, 'w') as target_file: |
| 117 if sep == '': | 165 target_file.write( |
| 118 raise UserError('Generated file %s does not have ' | 166 ('/* native_client/%s\n' |
| 119 'header comment block' % source_filename) | 167 ' * THIS FILE IS AUTO-GENERATED. DO NOT EDIT.\n' |
| 120 target_file.write(rest) | 168 ' * Compiled for %s mode.\n' |
| 169 ' */') % (target_filename, architecture)) | |
| 121 | 170 |
| 171 target_file.write(rest) | |
| 172 | |
| 173 # inject comments and place files to appropriate dir | |
| 122 env.Command( | 174 env.Command( |
| 123 target=c_full_filename, | 175 target=c_full_filename, |
| 124 source=['%s/%s' % (rl_src_dir, c_file)], | 176 source=['%s/%s' % (rl_src_dir, c_file)], |
| 125 action=InjectGeneratedFileHeader | 177 action=InjectGeneratedFileHeader |
| 126 ) | 178 ) |
| 127 | 179 |
| 128 return rl_file, c_file, c_full_filename | 180 return rl_file, c_file, c_full_filename |
| 129 | 181 |
| 130 decoder32 = MakeAutomaton( | 182 decoder32 = MakeAutomaton( |
| 131 '32', 'decoder', | 183 '32', 'decoder', |
| 132 'check_access,opcode,parse_operands_states,mark_data_fields', | 184 'check_access,opcode,parse_operands_states,mark_data_fields', |
| 133 '-T0') | 185 '-T0') |
| 134 validator32 = MakeAutomaton( | 186 validator32 = MakeAutomaton( |
| 135 '32', 'validator', | 187 '32', 'validator', |
| 136 ('check_access,opcode,parse_operands,parse_operands_states,' | 188 ('check_access,opcode,parse_operands,parse_operands_states,' |
| 137 'instruction_name,mark_data_fields,nacl-forbidden,' | 189 'instruction_name,mark_data_fields,nacl-forbidden,' |
| 138 'imm_operand_action,rel_operand_action'), | 190 'imm_operand_action,rel_operand_action'), |
| 139 '-G2') | 191 '-G2') |
| 140 decoder64 = MakeAutomaton( | 192 decoder64 = MakeAutomaton( |
| 141 '64', 'decoder', | 193 '64', 'decoder', |
| 142 'check_access,opcode,parse_operands_states,mark_data_fields', | 194 'check_access,opcode,parse_operands_states,mark_data_fields', |
| 143 '-T0') | 195 '-T0') |
| 144 validator64 = MakeAutomaton( | 196 validator64 = MakeAutomaton( |
| 145 '64', 'validator', | 197 '64', 'validator', |
| 146 ('opcode,instruction_name,mark_data_fields,imm_operand_action,' | 198 ('opcode,instruction_name,mark_data_fields,imm_operand_action,' |
| 147 'rel_operand_action,nacl-forbidden,parse_nonwrite_registers,' | 199 'rel_operand_action,nacl-forbidden,parse_nonwrite_registers,' |
| 148 'parse_x87_operands,parse_mmx_operands,parse_xmm_operands,' | 200 'parse_x87_operands,parse_mmx_operands,parse_xmm_operands,' |
| 149 'parse_ymm_operands,parse_relative_operands,' | 201 'parse_ymm_operands,parse_relative_operands,' |
| 150 'parse_immediate_operands,parse_operands_states,' | 202 'parse_immediate_operands,parse_operands_states,' |
| 151 'parse_operand_positions'), | 203 'parse_operand_positions'), |
| 152 '-GT2') | 204 '-GT2') |
| 153 | 205 |
| 154 automata = list(decoder32 + validator32 + decoder64 + validator64) | 206 automata = list(decoder32 + validator32 + decoder64 + validator64) |
| 155 | 207 |
| 208 | |
| 209 # Generate checkdecoder test | |
| 210 | |
| 211 test_env = env.Clone() | |
| 212 test_env.Append( | |
| 213 CCFLAGS=['-g', '-Wno-unused-function'], | |
| 214 LINKFLAGS='-g', | |
| 215 CPPPATH='unreviewed') | |
| 216 | |
| 217 test_dfa_object = test_env.Object('unreviewed/test_dfa.c') | |
| 218 | |
| 219 check_decoders = [] | |
| 220 | |
| 221 for bits in ('32', '64'): | |
| 222 (one_valid_instr_rl,) = env.Command( | |
| 223 target='one_valid_instruction_x86_%s.rl'%bits, | |
| 224 source=[gen_dfa]+INST_DEFS, | |
| 225 action=('${SOURCES[0]} -o ${TARGET} %s ' | |
| 226 '-d check_access,rex_prefix,vex_prefix,opcode ' | |
| 227 '-d parse_operands_states,parse_operands,instruction_name ' | |
| 228 '%s')%( | |
| 229 ' '.join('${SOURCES[%d]}'%(i+1) for i in range(len(INST_DEFS))), | |
| 230 {'32': '', '64': '-m amd64'}[bits]) | |
|
khim
2012/08/07 09:24:22
Please add explicit "-m ia32"
Vlad Shcherbina
2012/08/07 11:01:57
Done.
| |
| 231 ) | |
| 232 | |
| 233 include_dir = one_valid_instr_rl.dir.get_abspath() | |
| 234 | |
| 235 (one_instr_dot,) = env.Command( | |
| 236 target='one_instruction_x86_%s.dot'%bits, | |
| 237 source=['unreviewed/one_instruction_x86_%s.rl'%bits, one_valid_instr_rl] , | |
|
khim
2012/08/07 09:24:22
Long line
Vlad Shcherbina
2012/08/07 11:01:57
Done.
| |
| 238 action=[ | |
| 239 '%s -V -I%s ${SOURCES[0]} -o ${TARGET}'% | |
| 240 (ragel_binary, include_dir)] | |
| 241 ) | |
| 242 | |
| 243 test_dfa_transitions = test_env.Command( | |
| 244 target='test_dfa_transitions_x86_%s.c'%bits, | |
| 245 source=['unreviewed/parse_dfa.py', one_instr_dot], | |
| 246 action='python ${SOURCES[0]} <"${SOURCES[1]}" >"${TARGET}"' | |
| 247 ) | |
| 248 | |
| 249 unoptimized_env = test_env.Clone() | |
| 250 unoptimized_env.Append(CFLAGS='-O0') # does it make any difference? | |
|
khim
2012/08/07 09:24:22
I don't think it's big deal, really.
The whole te
Vlad Shcherbina
2012/08/07 11:01:57
Then I remove it to make config simpler.
| |
| 251 test_dfa_transitions_object = unoptimized_env.Object(test_dfa_transitions) | |
| 252 | |
| 253 test_dfa = test_env.ComponentProgram( | |
| 254 'test_dfa_x86_%s'%bits, | |
| 255 [test_dfa_object, test_dfa_transitions_object]) | |
| 256 | |
| 257 gas =File("#/../third_party/binutils/as-new") | |
|
khim
2012/08/07 09:24:22
Please rename it to as.linux
as-new is some wart
Vlad Shcherbina
2012/08/07 11:01:57
Done.
| |
| 258 objdump =File("#/../third_party/binutils/objdump") | |
|
khim
2012/08/07 09:24:22
This should be objdump.linux
Vlad Shcherbina
2012/08/07 11:01:57
Done.
| |
| 259 | |
| 260 fast_temp_for_test = '/dev/shm' | |
| 261 | |
| 262 (check_decoder,) = env.Command( | |
| 263 target='objdump_test_fake_file_%s'%bits, | |
| 264 source=[ | |
| 265 'unreviewed/run_objdump_test.py', | |
| 266 decoder_test, | |
| 267 'unreviewed/decoder_test_one_file.sh', | |
| 268 test_dfa, | |
| 269 ], | |
| 270 action=[( | |
| 271 'python ${SOURCES[0]} ' | |
| 272 '--gas="%s --%s" ' | |
| 273 '--objdump="%s" ' | |
| 274 '--decoder="${SOURCES[1]}" ' | |
| 275 '--tester="${SOURCES[2]}" ' | |
| 276 '--nthreads=`cat /proc/cpuinfo | grep processor | wc -l` ' #TODO: re move | |
|
khim
2012/08/07 09:24:22
Long line
Vlad Shcherbina
2012/08/07 11:01:57
Done.
| |
| 277 '-- ' | |
| 278 '"${SOURCES[3]}" "%s"' | |
| 279 )%(gas, bits, objdump, fast_temp_for_test), | |
| 280 ]) | |
| 281 check_decoders.append(check_decoder) | |
| 282 | |
| 283 SideEffect(fast_temp_for_test, check_decoders) | |
| 284 | |
| 156 env.AlwaysBuild(env.Alias('dfagen', automata)) | 285 env.AlwaysBuild(env.Alias('dfagen', automata)) |
| 157 env.AlwaysBuild(env.Alias('dfaclean', action=map(Delete, automata))) | 286 env.AlwaysBuild(env.Alias('dfaclean', action=map(Delete, automata))) |
| 158 | 287 env.AlwaysBuild(env.Alias('dfacheckdecoder', check_decoders)) |
| 159 # Generate 32 and 64 bit versions of decoders and validators. Both libraries | |
| 160 # are used for command-line decoder and validator those detect specific | |
| 161 # architecture of the ELF file provided. | |
| 162 env.ComponentLibrary('dfa_validate_x86_32', | |
| 163 ['gen/validator_x86_32.c']) | |
| 164 env.ComponentLibrary('dfa_validate_x86_64', | |
| 165 ['gen/validator_x86_64.c']) | |
| 166 env.ComponentLibrary('dfa_decode_x86_32', | |
| 167 ['gen/decoder_x86_32.c']) | |
| 168 env.ComponentLibrary('dfa_decode_x86_64', | |
| 169 ['gen/decoder_x86_64.c']) | |
| 170 | |
| 171 # Glue library called from service runtime. The source file depends on the | |
| 172 # target architecture. | |
| 173 caller_lib_bits = None | |
| 174 if env.Bit('target_x86_32'): | |
| 175 caller_lib_bits = '32' | |
| 176 if env.Bit('target_x86_64'): | |
| 177 caller_lib_bits = '64' | |
| 178 if caller_lib_bits: | |
| 179 caller_lib = 'dfa_validate_caller_x86_%s' % caller_lib_bits | |
| 180 env.ComponentLibrary(caller_lib, | |
| 181 ['unreviewed/dfa_validate_%s.c' % caller_lib_bits]) | |
| 182 | |
| 183 # Command-line decoder. | |
| 184 env.ComponentProgram( | |
| 185 'decoder_test', | |
| 186 ['unreviewed/decoder_test.c'], | |
| 187 EXTRA_LIBS=['dfa_decode_x86_32', 'dfa_decode_x86_64']) | |
| 188 | |
| 189 # Command-line validator. | |
| 190 validator_test_exe = env.ComponentProgram( | |
| 191 'validator_test', | |
| 192 ['unreviewed/validator_test.c'], | |
| 193 EXTRA_LIBS=['dfa_validate_x86_32', 'dfa_validate_x86_64']) | |
| 194 | |
| 195 # Python-based regression test. TODO(pasko): remove it when validator_tests are | |
| 196 # migrated to be able to run with the new validator. | |
| 197 if env.Bit('validator_ragel'): | |
| 198 test_node = env.CommandTest('validator_test_py.out', | |
| 199 command=['${PYTHON}', | |
| 200 env.File('unreviewed/validator_test.py'), | |
| 201 validator_test_exe]) | |
| 202 env.AddNodeToTestSuite(test_node, ['small_tests'], 'run_validator_test_py') | |
| OLD | NEW |