1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# Copyright 2020 The Chromium OS Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Run full bisection test.""" 8 9from __future__ import print_function 10 11import argparse 12import os 13import sys 14 15from cros_utils import command_executer 16 17TEST_DIR = 'full_bisect_test' 18DEFAULT_BISECT_DIR = '/tmp/sysroot_bisect' 19 20 21def populate_good_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR): 22 # 'make clean' 23 work_dir = os.path.join(top_dir, TEST_DIR, 'work') 24 cmd = 'rm -f %s/*.o' % work_dir 25 status = ce.RunCommand(cmd) 26 if status != 0: 27 print('Error trying to clean out work directory: %s' % cmd) 28 return status 29 30 # set up the 'good' source files 31 script = os.path.join(top_dir, TEST_DIR, 'make_sources_good.sh') 32 status = ce.RunCommand(script) 33 if status != 0: 34 print('Error setting up "good" source files: %s' % script) 35 return status 36 37 export_bisect = 'export BISECT_DIR=%s; ' % bisect_dir 38 # build the good source files 39 script_path = os.path.join(top_dir, TEST_DIR) 40 if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'): 41 build_script = 'chromeos_build.sh' 42 else: 43 build_script = 'build.sh' 44 cmd = ('%s export BISECT_STAGE=POPULATE_GOOD; pushd %s; ./%s; popd' % 45 (export_bisect, script_path, build_script)) 46 status = ce.RunCommand(cmd) 47 return status 48 49 50def populate_bad_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR): 51 # 'make clean' 52 work_dir = os.path.join(top_dir, TEST_DIR, 'work') 53 cmd = 'rm -f %s/*.o' % work_dir 54 status = ce.RunCommand(cmd) 55 if status != 0: 56 print('Error trying to clean out work directory: %s' % cmd) 57 return status 58 59 # set up the 'bad' source files 60 script = os.path.join(top_dir, TEST_DIR, 'make_sources_bad.sh') 61 status = ce.RunCommand(script) 62 if status != 0: 63 print('Error setting up "bad" source files: %s' % script) 64 return status 65 66 export_bisect = 'export BISECT_DIR=%s; ' % bisect_dir 67 # build the bad source files 68 script_path = os.path.join(top_dir, TEST_DIR) 69 if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'): 70 build_script = 'chromeos_build.sh' 71 else: 72 build_script = 'build.sh' 73 cmd = ('%s export BISECT_STAGE=POPULATE_BAD; pushd %s; ./%s ; popd' % 74 (export_bisect, script_path, build_script)) 75 status = ce.RunCommand(cmd) 76 return status 77 78 79def run_main_bisection_test(top_dir, ce): 80 test_script = os.path.join(top_dir, TEST_DIR, 'main-bisect-test.sh') 81 status = ce.RunCommand(test_script) 82 return status 83 84 85def verify_compiler_and_wrapper(): 86 # We don't need to do any special setup if running inside a ChromeOS 87 # chroot. 88 if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'): 89 return True 90 91 message = """ 92*** IMPORTANT --- READ THIS CAREFULLY!! *** 93 94This test uses the command 'gcc' to compile the good/bad versions of the 95source program. BEFORE you can run this script you must make sure that 96your compiler wrapper is in the right place, with the right name, so that 97a call to 'gcc' will go through your compiler wrapper and "do the right 98thing". 99 100Is your compiler wrapper properly set up? [Y/n] 101""" 102 103 print(message) 104 inp = sys.stdin.readline() 105 inp = inp.strip() 106 inp = inp.lower() 107 return not inp or inp == 'y' or inp == 'yes' 108 109 110def Main(argv): 111 parser = argparse.ArgumentParser() 112 parser.add_argument( 113 '--dir', 114 dest='directory', 115 help='Bisection work tree, where good & bad object ' 116 'files go. Default is /tmp/sysroot_bisect') 117 118 options = parser.parse_args(argv) 119 120 # Make sure the compiler wrapper & soft links are properly set up. 121 wrapper_is_setup = verify_compiler_and_wrapper() 122 if not wrapper_is_setup: 123 print('Exiting now. Please re-run after you have set up the compiler ' 124 'wrapper.') 125 return 0 126 127 # Make sure we're in the correct directory for running this test. 128 cwd = os.getcwd() 129 if not os.path.exists(os.path.join(cwd, 'full_bisect_test')): 130 print('Error: Wrong directory. This script must be run from the top level' 131 ' of the binary_search_tool tree (under toolchain_utils).') 132 return 1 133 134 ce = command_executer.GetCommandExecuter() 135 bisect_dir = options.directory 136 if not bisect_dir: 137 bisect_dir = DEFAULT_BISECT_DIR 138 139 # Make sure BISECT_DIR is clean 140 if os.path.exists(bisect_dir): 141 cmd = 'rm -Rf %s/*' % bisect_dir 142 retv = ce.RunCommand(cmd) 143 if retv != 0: 144 return retv 145 146 retv = populate_good_files(cwd, ce, bisect_dir) 147 if retv != 0: 148 return retv 149 150 retv = populate_bad_files(cwd, ce, bisect_dir) 151 if retv != 0: 152 return retv 153 154 # Set up good/bad work soft links 155 cmd = ('rm -f %s/%s/good-objects; ln -s %s/good %s/%s/good-objects' % 156 (cwd, TEST_DIR, bisect_dir, cwd, TEST_DIR)) 157 158 status = ce.RunCommand(cmd) 159 if status != 0: 160 print('Error executing: %s; exiting now.' % cmd) 161 return status 162 163 cmd = ('rm -f %s/%s/bad-objects; ln -s %s/bad %s/%s/bad-objects' % 164 (cwd, TEST_DIR, bisect_dir, cwd, TEST_DIR)) 165 166 status = ce.RunCommand(cmd) 167 if status != 0: 168 print('Error executing: %s; exiting now.' % cmd) 169 return status 170 171 retv = run_main_bisection_test(cwd, ce) 172 return retv 173 174 175if __name__ == '__main__': 176 retval = Main(sys.argv[1:]) 177 sys.exit(retval) 178