| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | #!/usr/bin/perl -w | 
 | 2 | # | 
 | 3 | # Copyright 2015 - Steven Rostedt, Red Hat Inc. | 
 | 4 | # Copyright 2017 - Steven Rostedt, VMware, Inc. | 
 | 5 | # | 
 | 6 | # Licensed under the terms of the GNU GPL License version 2 | 
 | 7 | # | 
 | 8 |  | 
 | 9 | # usage: | 
 | 10 | #  config-bisect.pl [options] good-config bad-config [good|bad] | 
 | 11 | # | 
 | 12 |  | 
 | 13 | # Compares a good config to a bad config, then takes half of the diffs | 
 | 14 | # and produces a config that is somewhere between the good config and | 
 | 15 | # the bad config. That is, the resulting config will start with the | 
 | 16 | # good config and will try to make half of the differences of between | 
 | 17 | # the good and bad configs match the bad config. It tries because of | 
 | 18 | # dependencies between the two configs it may not be able to change | 
 | 19 | # exactly half of the configs that are different between the two config | 
 | 20 | # files. | 
 | 21 |  | 
 | 22 | # Here's a normal way to use it: | 
 | 23 | # | 
 | 24 | #  $ cd /path/to/linux/kernel | 
 | 25 | #  $ config-bisect.pl /path/to/good/config /path/to/bad/config | 
 | 26 |  | 
 | 27 | # This will now pull in good config (blowing away .config in that directory | 
 | 28 | # so do not make that be one of the good or bad configs), and then | 
 | 29 | # build the config with "make oldconfig" to make sure it matches the | 
 | 30 | # current kernel. It will then store the configs in that result for | 
 | 31 | # the good config. It does the same for the bad config as well. | 
 | 32 | # The algorithm will run, merging half of the differences between | 
 | 33 | # the two configs and building them with "make oldconfig" to make sure | 
 | 34 | # the result changes (dependencies may reset changes the tool had made). | 
 | 35 | # It then copies the result of its good config to /path/to/good/config.tmp | 
 | 36 | # and the bad config to /path/to/bad/config.tmp (just appends ".tmp" to the | 
 | 37 | # files passed in). And the ".config" that you should test will be in | 
 | 38 | # directory | 
 | 39 |  | 
 | 40 | # After the first run, determine if the result is good or bad then | 
 | 41 | # run the same command appending the result | 
 | 42 |  | 
 | 43 | # For good results: | 
 | 44 | #  $ config-bisect.pl /path/to/good/config /path/to/bad/config good | 
 | 45 |  | 
 | 46 | # For bad results: | 
 | 47 | #  $ config-bisect.pl /path/to/good/config /path/to/bad/config bad | 
 | 48 |  | 
 | 49 | # Do not change the good-config or bad-config, config-bisect.pl will | 
 | 50 | # copy the good-config to a temp file with the same name as good-config | 
 | 51 | # but with a ".tmp" after it. It will do the same with the bad-config. | 
 | 52 |  | 
 | 53 | # If "good" or "bad" is not stated at the end, it will copy the good and | 
 | 54 | # bad configs to the .tmp versions. If a .tmp version already exists, it will | 
 | 55 | # warn before writing over them (-r will not warn, and just write over them). | 
 | 56 | # If the last config is labeled "good", then it will copy it to the good .tmp | 
 | 57 | # version. If the last config is labeled "bad", it will copy it to the bad | 
 | 58 | # .tmp version. It will continue this until it can not merge the two any more | 
 | 59 | # without the result being equal to either the good or bad .tmp configs. | 
 | 60 |  | 
 | 61 | my $start = 0; | 
 | 62 | my $val = ""; | 
 | 63 |  | 
 | 64 | my $pwd = `pwd`; | 
 | 65 | chomp $pwd; | 
 | 66 | my $tree = $pwd; | 
 | 67 | my $build; | 
 | 68 |  | 
 | 69 | my $output_config; | 
 | 70 | my $reset_bisect; | 
 | 71 |  | 
 | 72 | sub usage { | 
 | 73 |     print << "EOF" | 
 | 74 |  | 
 | 75 | usage: config-bisect.pl [-l linux-tree][-b build-dir] good-config bad-config [good|bad] | 
 | 76 |   -l [optional] define location of linux-tree (default is current directory) | 
 | 77 |   -b [optional] define location to build (O=build-dir) (default is linux-tree) | 
 | 78 |   good-config the config that is considered good | 
 | 79 |   bad-config the config that does not work | 
 | 80 |   "good" add this if the last run produced a good config | 
 | 81 |   "bad" add this if the last run produced a bad config | 
 | 82 |   If "good" or "bad" is not specified, then it is the start of a new bisect | 
 | 83 |  | 
 | 84 |   Note, each run will create copy of good and bad configs with ".tmp" appended. | 
 | 85 |  | 
 | 86 | EOF | 
 | 87 | ; | 
 | 88 |  | 
 | 89 |     exit(-1); | 
 | 90 | } | 
 | 91 |  | 
 | 92 | sub doprint { | 
 | 93 |     print @_; | 
 | 94 | } | 
 | 95 |  | 
 | 96 | sub dodie { | 
 | 97 |     doprint "CRITICAL FAILURE... ", @_, "\n"; | 
 | 98 |  | 
 | 99 |     die @_, "\n"; | 
 | 100 | } | 
 | 101 |  | 
 | 102 | sub expand_path { | 
 | 103 |     my ($file) = @_; | 
 | 104 |  | 
 | 105 |     if ($file =~ m,^/,) { | 
 | 106 | 	return $file; | 
 | 107 |     } | 
 | 108 |     return "$pwd/$file"; | 
 | 109 | } | 
 | 110 |  | 
 | 111 | sub read_prompt { | 
 | 112 |     my ($cancel, $prompt) = @_; | 
 | 113 |  | 
 | 114 |     my $ans; | 
 | 115 |  | 
 | 116 |     for (;;) { | 
 | 117 | 	if ($cancel) { | 
 | 118 | 	    print "$prompt [y/n/C] "; | 
 | 119 | 	} else { | 
 | 120 | 	    print "$prompt [y/N] "; | 
 | 121 | 	} | 
 | 122 | 	$ans = <STDIN>; | 
 | 123 | 	chomp $ans; | 
 | 124 | 	if ($ans =~ /^\s*$/) { | 
 | 125 | 	    if ($cancel) { | 
 | 126 | 		$ans = "c"; | 
 | 127 | 	    } else { | 
 | 128 | 		$ans = "n"; | 
 | 129 | 	    } | 
 | 130 | 	} | 
 | 131 | 	last if ($ans =~ /^y$/i || $ans =~ /^n$/i); | 
 | 132 | 	if ($cancel) { | 
 | 133 | 	    last if ($ans =~ /^c$/i); | 
 | 134 | 	    print "Please answer either 'y', 'n' or 'c'.\n"; | 
 | 135 | 	} else { | 
 | 136 | 	    print "Please answer either 'y' or 'n'.\n"; | 
 | 137 | 	} | 
 | 138 |     } | 
 | 139 |     if ($ans =~ /^c/i) { | 
 | 140 | 	exit; | 
 | 141 |     } | 
 | 142 |     if ($ans !~ /^y$/i) { | 
 | 143 | 	return 0; | 
 | 144 |     } | 
 | 145 |     return 1; | 
 | 146 | } | 
 | 147 |  | 
 | 148 | sub read_yn { | 
 | 149 |     my ($prompt) = @_; | 
 | 150 |  | 
 | 151 |     return read_prompt 0, $prompt; | 
 | 152 | } | 
 | 153 |  | 
 | 154 | sub read_ync { | 
 | 155 |     my ($prompt) = @_; | 
 | 156 |  | 
 | 157 |     return read_prompt 1, $prompt; | 
 | 158 | } | 
 | 159 |  | 
 | 160 | sub run_command { | 
 | 161 |     my ($command, $redirect) = @_; | 
 | 162 |     my $start_time; | 
 | 163 |     my $end_time; | 
 | 164 |     my $dord = 0; | 
 | 165 |     my $pid; | 
 | 166 |  | 
 | 167 |     $start_time = time; | 
 | 168 |  | 
 | 169 |     doprint("$command ... "); | 
 | 170 |  | 
 | 171 |     $pid = open(CMD, "$command 2>&1 |") or | 
 | 172 | 	dodie "unable to exec $command"; | 
 | 173 |  | 
 | 174 |     if (defined($redirect)) { | 
 | 175 | 	open (RD, ">$redirect") or | 
 | 176 | 	    dodie "failed to write to redirect $redirect"; | 
 | 177 | 	$dord = 1; | 
 | 178 |     } | 
 | 179 |  | 
 | 180 |     while (<CMD>) { | 
 | 181 | 	print RD  if ($dord); | 
 | 182 |     } | 
 | 183 |  | 
 | 184 |     waitpid($pid, 0); | 
 | 185 |     my $failed = $?; | 
 | 186 |  | 
 | 187 |     close(CMD); | 
 | 188 |     close(RD)  if ($dord); | 
 | 189 |  | 
 | 190 |     $end_time = time; | 
 | 191 |     my $delta = $end_time - $start_time; | 
 | 192 |  | 
 | 193 |     if ($delta == 1) { | 
 | 194 | 	doprint "[1 second] "; | 
 | 195 |     } else { | 
 | 196 | 	doprint "[$delta seconds] "; | 
 | 197 |     } | 
 | 198 |  | 
 | 199 |     if ($failed) { | 
 | 200 | 	doprint "FAILED!\n"; | 
 | 201 |     } else { | 
 | 202 | 	doprint "SUCCESS\n"; | 
 | 203 |     } | 
 | 204 |  | 
 | 205 |     return !$failed; | 
 | 206 | } | 
 | 207 |  | 
 | 208 | ###### CONFIG BISECT ###### | 
 | 209 |  | 
 | 210 | # config_ignore holds the configs that were set (or unset) for | 
 | 211 | # a good config and we will ignore these configs for the rest | 
 | 212 | # of a config bisect. These configs stay as they were. | 
 | 213 | my %config_ignore; | 
 | 214 |  | 
 | 215 | # config_set holds what all configs were set as. | 
 | 216 | my %config_set; | 
 | 217 |  | 
 | 218 | # config_off holds the set of configs that the bad config had disabled. | 
 | 219 | # We need to record them and set them in the .config when running | 
 | 220 | # olddefconfig, because olddefconfig keeps the defaults. | 
 | 221 | my %config_off; | 
 | 222 |  | 
 | 223 | # config_off_tmp holds a set of configs to turn off for now | 
 | 224 | my @config_off_tmp; | 
 | 225 |  | 
 | 226 | # config_list is the set of configs that are being tested | 
 | 227 | my %config_list; | 
 | 228 | my %null_config; | 
 | 229 |  | 
 | 230 | my %dependency; | 
 | 231 |  | 
 | 232 | my $make; | 
 | 233 |  | 
 | 234 | sub make_oldconfig { | 
 | 235 |  | 
 | 236 |     if (!run_command "$make olddefconfig") { | 
 | 237 | 	# Perhaps olddefconfig doesn't exist in this version of the kernel | 
 | 238 | 	# try oldnoconfig | 
 | 239 | 	doprint "olddefconfig failed, trying make oldnoconfig\n"; | 
 | 240 | 	if (!run_command "$make oldnoconfig") { | 
 | 241 | 	    doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; | 
 | 242 | 	    # try a yes '' | oldconfig | 
 | 243 | 	    run_command "yes '' | $make oldconfig" or | 
 | 244 | 		dodie "failed make config oldconfig"; | 
 | 245 | 	} | 
 | 246 |     } | 
 | 247 | } | 
 | 248 |  | 
 | 249 | sub assign_configs { | 
 | 250 |     my ($hash, $config) = @_; | 
 | 251 |  | 
 | 252 |     doprint "Reading configs from $config\n"; | 
 | 253 |  | 
 | 254 |     open (IN, $config) | 
 | 255 | 	or dodie "Failed to read $config"; | 
 | 256 |  | 
 | 257 |     while (<IN>) { | 
 | 258 | 	chomp; | 
 | 259 | 	if (/^((CONFIG\S*)=.*)/) { | 
 | 260 | 	    ${$hash}{$2} = $1; | 
 | 261 | 	} elsif (/^(# (CONFIG\S*) is not set)/) { | 
 | 262 | 	    ${$hash}{$2} = $1; | 
 | 263 | 	} | 
 | 264 |     } | 
 | 265 |  | 
 | 266 |     close(IN); | 
 | 267 | } | 
 | 268 |  | 
 | 269 | sub process_config_ignore { | 
 | 270 |     my ($config) = @_; | 
 | 271 |  | 
 | 272 |     assign_configs \%config_ignore, $config; | 
 | 273 | } | 
 | 274 |  | 
 | 275 | sub get_dependencies { | 
 | 276 |     my ($config) = @_; | 
 | 277 |  | 
 | 278 |     my $arr = $dependency{$config}; | 
 | 279 |     if (!defined($arr)) { | 
 | 280 | 	return (); | 
 | 281 |     } | 
 | 282 |  | 
 | 283 |     my @deps = @{$arr}; | 
 | 284 |  | 
 | 285 |     foreach my $dep (@{$arr}) { | 
 | 286 | 	print "ADD DEP $dep\n"; | 
 | 287 | 	@deps = (@deps, get_dependencies $dep); | 
 | 288 |     } | 
 | 289 |  | 
 | 290 |     return @deps; | 
 | 291 | } | 
 | 292 |  | 
 | 293 | sub save_config { | 
 | 294 |     my ($pc, $file) = @_; | 
 | 295 |  | 
 | 296 |     my %configs = %{$pc}; | 
 | 297 |  | 
 | 298 |     doprint "Saving configs into $file\n"; | 
 | 299 |  | 
 | 300 |     open(OUT, ">$file") or dodie "Can not write to $file"; | 
 | 301 |  | 
 | 302 |     foreach my $config (keys %configs) { | 
 | 303 | 	print OUT "$configs{$config}\n"; | 
 | 304 |     } | 
 | 305 |     close(OUT); | 
 | 306 | } | 
 | 307 |  | 
 | 308 | sub create_config { | 
 | 309 |     my ($name, $pc) = @_; | 
 | 310 |  | 
 | 311 |     doprint "Creating old config from $name configs\n"; | 
 | 312 |  | 
 | 313 |     save_config $pc, $output_config; | 
 | 314 |  | 
 | 315 |     make_oldconfig; | 
 | 316 | } | 
 | 317 |  | 
 | 318 | # compare two config hashes, and return configs with different vals. | 
 | 319 | # It returns B's config values, but you can use A to see what A was. | 
 | 320 | sub diff_config_vals { | 
 | 321 |     my ($pa, $pb) = @_; | 
 | 322 |  | 
 | 323 |     # crappy Perl way to pass in hashes. | 
 | 324 |     my %a = %{$pa}; | 
 | 325 |     my %b = %{$pb}; | 
 | 326 |  | 
 | 327 |     my %ret; | 
 | 328 |  | 
 | 329 |     foreach my $item (keys %a) { | 
 | 330 | 	if (defined($b{$item}) && $b{$item} ne $a{$item}) { | 
 | 331 | 	    $ret{$item} = $b{$item}; | 
 | 332 | 	} | 
 | 333 |     } | 
 | 334 |  | 
 | 335 |     return %ret; | 
 | 336 | } | 
 | 337 |  | 
 | 338 | # compare two config hashes and return the configs in B but not A | 
 | 339 | sub diff_configs { | 
 | 340 |     my ($pa, $pb) = @_; | 
 | 341 |  | 
 | 342 |     my %ret; | 
 | 343 |  | 
 | 344 |     # crappy Perl way to pass in hashes. | 
 | 345 |     my %a = %{$pa}; | 
 | 346 |     my %b = %{$pb}; | 
 | 347 |  | 
 | 348 |     foreach my $item (keys %b) { | 
 | 349 | 	if (!defined($a{$item})) { | 
 | 350 | 	    $ret{$item} = $b{$item}; | 
 | 351 | 	} | 
 | 352 |     } | 
 | 353 |  | 
 | 354 |     return %ret; | 
 | 355 | } | 
 | 356 |  | 
 | 357 | # return if two configs are equal or not | 
 | 358 | # 0 is equal +1 b has something a does not | 
 | 359 | # +1 if a and b have a different item. | 
 | 360 | # -1 if a has something b does not | 
 | 361 | sub compare_configs { | 
 | 362 |     my ($pa, $pb) = @_; | 
 | 363 |  | 
 | 364 |     my %ret; | 
 | 365 |  | 
 | 366 |     # crappy Perl way to pass in hashes. | 
 | 367 |     my %a = %{$pa}; | 
 | 368 |     my %b = %{$pb}; | 
 | 369 |  | 
 | 370 |     foreach my $item (keys %b) { | 
 | 371 | 	if (!defined($a{$item})) { | 
 | 372 | 	    return 1; | 
 | 373 | 	} | 
 | 374 | 	if ($a{$item} ne $b{$item}) { | 
 | 375 | 	    return 1; | 
 | 376 | 	} | 
 | 377 |     } | 
 | 378 |  | 
 | 379 |     foreach my $item (keys %a) { | 
 | 380 | 	if (!defined($b{$item})) { | 
 | 381 | 	    return -1; | 
 | 382 | 	} | 
 | 383 |     } | 
 | 384 |  | 
 | 385 |     return 0; | 
 | 386 | } | 
 | 387 |  | 
 | 388 | sub process_failed { | 
 | 389 |     my ($config) = @_; | 
 | 390 |  | 
 | 391 |     doprint "\n\n***************************************\n"; | 
 | 392 |     doprint "Found bad config: $config\n"; | 
 | 393 |     doprint "***************************************\n\n"; | 
 | 394 | } | 
 | 395 |  | 
 | 396 | sub process_new_config { | 
 | 397 |     my ($tc, $nc, $gc, $bc) = @_; | 
 | 398 |  | 
 | 399 |     my %tmp_config = %{$tc}; | 
 | 400 |     my %good_configs = %{$gc}; | 
 | 401 |     my %bad_configs = %{$bc}; | 
 | 402 |  | 
 | 403 |     my %new_configs; | 
 | 404 |  | 
 | 405 |     my $runtest = 1; | 
 | 406 |     my $ret; | 
 | 407 |  | 
 | 408 |     create_config "tmp_configs", \%tmp_config; | 
 | 409 |     assign_configs \%new_configs, $output_config; | 
 | 410 |  | 
 | 411 |     $ret = compare_configs \%new_configs, \%bad_configs; | 
 | 412 |     if (!$ret) { | 
 | 413 | 	doprint "New config equals bad config, try next test\n"; | 
 | 414 | 	$runtest = 0; | 
 | 415 |     } | 
 | 416 |  | 
 | 417 |     if ($runtest) { | 
 | 418 | 	$ret = compare_configs \%new_configs, \%good_configs; | 
 | 419 | 	if (!$ret) { | 
 | 420 | 	    doprint "New config equals good config, try next test\n"; | 
 | 421 | 	    $runtest = 0; | 
 | 422 | 	} | 
 | 423 |     } | 
 | 424 |  | 
 | 425 |     %{$nc} = %new_configs; | 
 | 426 |  | 
 | 427 |     return $runtest; | 
 | 428 | } | 
 | 429 |  | 
 | 430 | sub convert_config { | 
 | 431 |     my ($config) = @_; | 
 | 432 |  | 
 | 433 |     if ($config =~ /^# (.*) is not set/) { | 
 | 434 | 	$config = "$1=n"; | 
 | 435 |     } | 
 | 436 |  | 
 | 437 |     $config =~ s/^CONFIG_//; | 
 | 438 |     return $config; | 
 | 439 | } | 
 | 440 |  | 
 | 441 | sub print_config { | 
 | 442 |     my ($sym, $config) = @_; | 
 | 443 |  | 
 | 444 |     $config = convert_config $config; | 
 | 445 |     doprint "$sym$config\n"; | 
 | 446 | } | 
 | 447 |  | 
 | 448 | sub print_config_compare { | 
 | 449 |     my ($good_config, $bad_config) = @_; | 
 | 450 |  | 
 | 451 |     $good_config = convert_config $good_config; | 
 | 452 |     $bad_config = convert_config $bad_config; | 
 | 453 |  | 
 | 454 |     my $good_value = $good_config; | 
 | 455 |     my $bad_value = $bad_config; | 
 | 456 |     $good_value =~ s/(.*)=//; | 
 | 457 |     my $config = $1; | 
 | 458 |  | 
 | 459 |     $bad_value =~ s/.*=//; | 
 | 460 |  | 
 | 461 |     doprint " $config $good_value -> $bad_value\n"; | 
 | 462 | } | 
 | 463 |  | 
 | 464 | # Pass in: | 
 | 465 | # $phalf: half of the configs names you want to add | 
 | 466 | # $oconfigs: The orginial configs to start with | 
 | 467 | # $sconfigs: The source to update $oconfigs with (from $phalf) | 
 | 468 | # $which: The name of which half that is updating (top / bottom) | 
 | 469 | # $type: The name of the source type (good / bad) | 
 | 470 | sub make_half { | 
 | 471 |     my ($phalf, $oconfigs, $sconfigs, $which, $type) = @_; | 
 | 472 |  | 
 | 473 |     my @half = @{$phalf}; | 
 | 474 |     my %orig_configs = %{$oconfigs}; | 
 | 475 |     my %source_configs = %{$sconfigs}; | 
 | 476 |  | 
 | 477 |     my %tmp_config = %orig_configs; | 
 | 478 |  | 
 | 479 |     doprint "Settings bisect with $which half of $type configs:\n"; | 
 | 480 |     foreach my $item (@half) { | 
 | 481 | 	doprint "Updating $item to $source_configs{$item}\n"; | 
 | 482 | 	$tmp_config{$item} = $source_configs{$item}; | 
 | 483 |     } | 
 | 484 |  | 
 | 485 |     return %tmp_config; | 
 | 486 | } | 
 | 487 |  | 
 | 488 | sub run_config_bisect { | 
 | 489 |     my ($pgood, $pbad) = @_; | 
 | 490 |  | 
 | 491 |     my %good_configs = %{$pgood}; | 
 | 492 |     my %bad_configs = %{$pbad}; | 
 | 493 |  | 
 | 494 |     my %diff_configs = diff_config_vals \%good_configs, \%bad_configs; | 
 | 495 |     my %b_configs = diff_configs \%good_configs, \%bad_configs; | 
 | 496 |     my %g_configs = diff_configs \%bad_configs, \%good_configs; | 
 | 497 |  | 
 | 498 |     # diff_arr is what is in both good and bad but are different (y->n) | 
 | 499 |     my @diff_arr = keys %diff_configs; | 
 | 500 |     my $len_diff = $#diff_arr + 1; | 
 | 501 |  | 
 | 502 |     # b_arr is what is in bad but not in good (has depends) | 
 | 503 |     my @b_arr = keys %b_configs; | 
 | 504 |     my $len_b = $#b_arr + 1; | 
 | 505 |  | 
 | 506 |     # g_arr is what is in good but not in bad | 
 | 507 |     my @g_arr = keys %g_configs; | 
 | 508 |     my $len_g = $#g_arr + 1; | 
 | 509 |  | 
 | 510 |     my $runtest = 0; | 
 | 511 |     my %new_configs; | 
 | 512 |     my $ret; | 
 | 513 |  | 
 | 514 |     # Look at the configs that are different between good and bad. | 
 | 515 |     # This does not include those that depend on other configs | 
 | 516 |     #  (configs depending on other configs that are not set would | 
 | 517 |     #   not show up even as a "# CONFIG_FOO is not set" | 
 | 518 |  | 
 | 519 |  | 
 | 520 |     doprint "# of configs to check:             $len_diff\n"; | 
 | 521 |     doprint "# of configs showing only in good: $len_g\n"; | 
 | 522 |     doprint "# of configs showing only in bad:  $len_b\n"; | 
 | 523 |  | 
 | 524 |     if ($len_diff > 0) { | 
 | 525 | 	# Now test for different values | 
 | 526 |  | 
 | 527 | 	doprint "Configs left to check:\n"; | 
 | 528 | 	doprint "  Good Config\t\t\tBad Config\n"; | 
 | 529 | 	doprint "  -----------\t\t\t----------\n"; | 
 | 530 | 	foreach my $item (@diff_arr) { | 
 | 531 | 	    doprint "  $good_configs{$item}\t$bad_configs{$item}\n"; | 
 | 532 | 	} | 
 | 533 |  | 
 | 534 | 	my $half = int($#diff_arr / 2); | 
 | 535 | 	my @tophalf = @diff_arr[0 .. $half]; | 
 | 536 |  | 
 | 537 | 	doprint "Set tmp config to be good config with some bad config values\n"; | 
 | 538 |  | 
 | 539 | 	my %tmp_config = make_half \@tophalf, \%good_configs, | 
 | 540 | 	    \%bad_configs, "top", "bad"; | 
 | 541 |  | 
 | 542 | 	$runtest = process_new_config \%tmp_config, \%new_configs, | 
 | 543 | 			    \%good_configs, \%bad_configs; | 
 | 544 |  | 
 | 545 | 	if (!$runtest) { | 
 | 546 | 	    doprint "Set tmp config to be bad config with some good config values\n"; | 
 | 547 |  | 
 | 548 | 	    my %tmp_config = make_half \@tophalf, \%bad_configs, | 
 | 549 | 		\%good_configs, "top", "good"; | 
 | 550 |  | 
 | 551 | 	    $runtest = process_new_config \%tmp_config, \%new_configs, | 
 | 552 | 		\%good_configs, \%bad_configs; | 
 | 553 | 	} | 
 | 554 |     } | 
 | 555 |  | 
 | 556 |     if (!$runtest && $len_diff > 0) { | 
 | 557 | 	# do the same thing, but this time with bottom half | 
 | 558 |  | 
 | 559 | 	my $half = int($#diff_arr / 2); | 
 | 560 | 	my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr]; | 
 | 561 |  | 
 | 562 | 	doprint "Set tmp config to be good config with some bad config values\n"; | 
 | 563 |  | 
 | 564 | 	my %tmp_config = make_half \@bottomhalf, \%good_configs, | 
 | 565 | 	    \%bad_configs, "bottom", "bad"; | 
 | 566 |  | 
 | 567 | 	$runtest = process_new_config \%tmp_config, \%new_configs, | 
 | 568 | 			    \%good_configs, \%bad_configs; | 
 | 569 |  | 
 | 570 | 	if (!$runtest) { | 
 | 571 | 	    doprint "Set tmp config to be bad config with some good config values\n"; | 
 | 572 |  | 
 | 573 | 	    my %tmp_config = make_half \@bottomhalf, \%bad_configs, | 
 | 574 | 		\%good_configs, "bottom", "good"; | 
 | 575 |  | 
 | 576 | 	    $runtest = process_new_config \%tmp_config, \%new_configs, | 
 | 577 | 		\%good_configs, \%bad_configs; | 
 | 578 | 	} | 
 | 579 |     } | 
 | 580 |  | 
 | 581 |     if ($runtest) { | 
 | 582 | 	make_oldconfig; | 
 | 583 | 	doprint "READY TO TEST .config IN $build\n"; | 
 | 584 | 	return 0; | 
 | 585 |     } | 
 | 586 |  | 
 | 587 |     doprint "\n%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n"; | 
 | 588 |     doprint "Hmm, can't make any more changes without making good == bad?\n"; | 
 | 589 |     doprint "Difference between good (+) and bad (-)\n"; | 
 | 590 |  | 
 | 591 |     foreach my $item (keys %bad_configs) { | 
 | 592 | 	if (!defined($good_configs{$item})) { | 
 | 593 | 	    print_config "-", $bad_configs{$item}; | 
 | 594 | 	} | 
 | 595 |     } | 
 | 596 |  | 
 | 597 |     foreach my $item (keys %good_configs) { | 
 | 598 | 	next if (!defined($bad_configs{$item})); | 
 | 599 | 	if ($good_configs{$item} ne $bad_configs{$item}) { | 
 | 600 | 	    print_config_compare $good_configs{$item}, $bad_configs{$item}; | 
 | 601 | 	} | 
 | 602 |     } | 
 | 603 |  | 
 | 604 |     foreach my $item (keys %good_configs) { | 
 | 605 | 	if (!defined($bad_configs{$item})) { | 
 | 606 | 	    print_config "+", $good_configs{$item}; | 
 | 607 | 	} | 
 | 608 |     } | 
 | 609 |     return -1; | 
 | 610 | } | 
 | 611 |  | 
 | 612 | sub config_bisect { | 
 | 613 |     my ($good_config, $bad_config) = @_; | 
 | 614 |     my $ret; | 
 | 615 |  | 
 | 616 |     my %good_configs; | 
 | 617 |     my %bad_configs; | 
 | 618 |     my %tmp_configs; | 
 | 619 |  | 
 | 620 |     doprint "Run good configs through make oldconfig\n"; | 
 | 621 |     assign_configs \%tmp_configs, $good_config; | 
 | 622 |     create_config "$good_config", \%tmp_configs; | 
 | 623 |     assign_configs \%good_configs, $output_config; | 
 | 624 |  | 
 | 625 |     doprint "Run bad configs through make oldconfig\n"; | 
 | 626 |     assign_configs \%tmp_configs, $bad_config; | 
 | 627 |     create_config "$bad_config", \%tmp_configs; | 
 | 628 |     assign_configs \%bad_configs, $output_config; | 
 | 629 |  | 
 | 630 |     save_config \%good_configs, $good_config; | 
 | 631 |     save_config \%bad_configs, $bad_config; | 
 | 632 |  | 
 | 633 |     return run_config_bisect \%good_configs, \%bad_configs; | 
 | 634 | } | 
 | 635 |  | 
 | 636 | while ($#ARGV >= 0) { | 
 | 637 |     if ($ARGV[0] !~ m/^-/) { | 
 | 638 | 	last; | 
 | 639 |     } | 
 | 640 |     my $opt = shift @ARGV; | 
 | 641 |  | 
 | 642 |     if ($opt eq "-b") { | 
 | 643 | 	$val = shift @ARGV; | 
 | 644 | 	if (!defined($val)) { | 
 | 645 | 	    die "-b requires value\n"; | 
 | 646 | 	} | 
 | 647 | 	$build = $val; | 
 | 648 |     } | 
 | 649 |  | 
 | 650 |     elsif ($opt eq "-l") { | 
 | 651 | 	$val = shift @ARGV; | 
 | 652 | 	if (!defined($val)) { | 
 | 653 | 	    die "-l requires value\n"; | 
 | 654 | 	} | 
 | 655 | 	$tree = $val; | 
 | 656 |     } | 
 | 657 |  | 
 | 658 |     elsif ($opt eq "-r") { | 
 | 659 | 	$reset_bisect = 1; | 
 | 660 |     } | 
 | 661 |  | 
 | 662 |     elsif ($opt eq "-h") { | 
 | 663 | 	usage; | 
 | 664 |     } | 
 | 665 |  | 
 | 666 |     else { | 
 | 667 | 	die "Unknow option $opt\n"; | 
 | 668 |     } | 
 | 669 | } | 
 | 670 |  | 
 | 671 | $build = $tree if (!defined($build)); | 
 | 672 |  | 
 | 673 | $tree = expand_path $tree; | 
 | 674 | $build = expand_path $build; | 
 | 675 |  | 
 | 676 | if ( ! -d $tree ) { | 
 | 677 |     die "$tree not a directory\n"; | 
 | 678 | } | 
 | 679 |  | 
 | 680 | if ( ! -d $build ) { | 
 | 681 |     die "$build not a directory\n"; | 
 | 682 | } | 
 | 683 |  | 
 | 684 | usage if $#ARGV < 1; | 
 | 685 |  | 
 | 686 | if ($#ARGV == 1) { | 
 | 687 |     $start = 1; | 
 | 688 | } elsif ($#ARGV == 2) { | 
 | 689 |     $val = $ARGV[2]; | 
 | 690 |     if ($val ne "good" && $val ne "bad") { | 
 | 691 | 	die "Unknown command '$val', bust be either \"good\" or \"bad\"\n"; | 
 | 692 |     } | 
 | 693 | } else { | 
 | 694 |     usage; | 
 | 695 | } | 
 | 696 |  | 
 | 697 | my $good_start = expand_path $ARGV[0]; | 
 | 698 | my $bad_start = expand_path $ARGV[1]; | 
 | 699 |  | 
 | 700 | my $good = "$good_start.tmp"; | 
 | 701 | my $bad = "$bad_start.tmp"; | 
 | 702 |  | 
 | 703 | $make = "make"; | 
 | 704 |  | 
 | 705 | if ($build ne $tree) { | 
 | 706 |     $make = "make O=$build" | 
 | 707 | } | 
 | 708 |  | 
 | 709 | $output_config = "$build/.config"; | 
 | 710 |  | 
 | 711 | if ($start) { | 
 | 712 |     if ( ! -f $good_start ) { | 
 | 713 | 	die "$good_start not found\n"; | 
 | 714 |     } | 
 | 715 |     if ( ! -f $bad_start ) { | 
 | 716 | 	die "$bad_start not found\n"; | 
 | 717 |     } | 
 | 718 |     if ( -f $good || -f $bad ) { | 
 | 719 | 	my $p = ""; | 
 | 720 |  | 
 | 721 | 	if ( -f $good ) { | 
 | 722 | 	    $p = "$good exists\n"; | 
 | 723 | 	} | 
 | 724 |  | 
 | 725 | 	if ( -f $bad ) { | 
 | 726 | 	    $p = "$p$bad exists\n"; | 
 | 727 | 	} | 
 | 728 |  | 
 | 729 | 	if (!defined($reset_bisect)) { | 
 | 730 | 	    if (!read_yn "${p}Overwrite and start new bisect anyway?") { | 
 | 731 | 		exit (-1); | 
 | 732 | 	    } | 
 | 733 | 	} | 
 | 734 |     } | 
 | 735 |     run_command "cp $good_start $good" or die "failed to copy to $good\n"; | 
 | 736 |     run_command "cp $bad_start $bad" or die "faield to copy to $bad\n"; | 
 | 737 | } else { | 
 | 738 |     if ( ! -f $good ) { | 
 | 739 | 	die "Can not find file $good\n"; | 
 | 740 |     } | 
 | 741 |     if ( ! -f $bad ) { | 
 | 742 | 	die "Can not find file $bad\n"; | 
 | 743 |     } | 
 | 744 |     if ($val eq "good") { | 
 | 745 | 	run_command "cp $output_config $good" or die "failed to copy $config to $good\n"; | 
 | 746 |     } elsif ($val eq "bad") { | 
 | 747 | 	run_command "cp $output_config $bad" or die "failed to copy $config to $bad\n"; | 
 | 748 |     } | 
 | 749 | } | 
 | 750 |  | 
 | 751 | chdir $tree || die "can't change directory to $tree"; | 
 | 752 |  | 
 | 753 | my $ret = config_bisect $good, $bad; | 
 | 754 |  | 
 | 755 | if (!$ret) { | 
 | 756 |     exit(0); | 
 | 757 | } | 
 | 758 |  | 
 | 759 | if ($ret > 0) { | 
 | 760 |     doprint "Cleaning temp files\n"; | 
 | 761 |     run_command "rm $good"; | 
 | 762 |     run_command "rm $bad"; | 
 | 763 |     exit(1); | 
 | 764 | } else { | 
 | 765 |     doprint "See good and bad configs for details:\n"; | 
 | 766 |     doprint "good: $good\n"; | 
 | 767 |     doprint "bad:  $bad\n"; | 
 | 768 |     doprint "%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n"; | 
 | 769 | } | 
 | 770 | exit(2); |