diff options
author | Amir Ayupov <aaupov@fb.com> | 2021-11-23 20:48:50 -0800 |
---|---|---|
committer | Maksim Panchenko <maks@fb.com> | 2021-11-23 20:48:50 -0800 |
commit | e4ccdfe84f8491f091171c255c814992e58b20a0 (patch) | |
tree | 9cab7bb2cbfce3551aade91c81c536b86ac7a217 /bolt/utils | |
parent | d474dbdfcb174a80ac6f96c996f2817740e0c65e (diff) | |
download | llvm-e4ccdfe84f8491f091171c255c814992e58b20a0.tar.gz |
[BOLT] Import bughunter script
Summary: Import the script and update it to use `-funcs-file-no-regex`
(cherry picked from FBD32636025)
Diffstat (limited to 'bolt/utils')
-rwxr-xr-x | bolt/utils/bughunter.sh | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/bolt/utils/bughunter.sh b/bolt/utils/bughunter.sh new file mode 100755 index 000000000000..12de9a2ec513 --- /dev/null +++ b/bolt/utils/bughunter.sh @@ -0,0 +1,264 @@ +#!/bin/bash +#===--------------- llvm/tools/llvm-bolt/utils/bughunter.sh ---------------===// +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===-----------------------------------------------------------------------===// +# +# This script attempts to narrow down llvm-bolt bug to a single function in the +# input binary. +# +# If such a function is found, llvm-bolt could be run just on this function +# to mitigate debugging process. +# +# The following envvars are used by this script: +# +# BOLT - path to llvm-bolt +# +# BOLT_OPTIONS - options to be used by llvm-bolt +# +# INPUT_BINARY - input for llvm-bolt +# +# PRE_COMMAND - command to execute prior to running optimized binary +# +# POST_COMMAND - command to filter results of running optimized binary +# +# TIMEOUT_OR_CMD - optional timeout or command on optimized binary command +# if the value is a number with an optional trailing letter +# [smhd] it is considered a paramter to "timeout", +# otherwise it's a shell command that wraps the optimized +# binary command. +# +# COMMAND_LINE - command line options to run optimized binary with +# +# IGNORE_ERROR - ignore error codes returned from optimized binary +# +# GOLD_FILE - file containing expected output from optimized binary +# +# FUNC_NAMES - if set, path to an initial list of function names to +# search. Otherwise, nm is used on the original binary. +# +# OFFLINE - if set, bughunter will produce the binaries but will not +# run them, and will depend on you telling whether it +# succeeded or not. +# +# MAX_FUNCS - if set, use -max-funcs to narrow down the offending +# function. if non-zero, start -max-funcs at $MAX_FUNCS +# otherwise, count the number of symbols in the binary. +# +# MAX_FUNCS_FLAG - BOLT command line option to use for MAX_FUNCS search. +# Default is -max-funcs. Can also be used for relocation +# debugging, e.g. -max-data-relocations. +# +# VERBOSE - if non-empty, set the script to echo mode. +# +BOLT=${BOLT:=llvm-bolt} + +ulimit -c 0 +set -o pipefail + +if [[ -n "$VERBOSE" ]]; then + set -x +fi + +if [[ ! -x $INPUT_BINARY ]] ; then + echo "INPUT_BINARY must be set to an executable file" + exit 1 +fi + +if [[ -z "$PRE_COMMAND" ]] ; then + PRE_COMMAND=':' +fi + +if [[ -z "$POST_COMMAND" ]] ; then + POST_COMMAND='cat' +fi + +if [[ -n "$TIMEOUT_OR_CMD" && $TIMEOUT_OR_CMD =~ ^[0-9]+[smhd]?$ ]] ; then + TIMEOUT_OR_CMD="timeout -s KILL $TIMEOUT_OR_CMD" +fi + +if [[ -z "$MAX_FUNCS_FLAG" ]] ; then + MAX_FUNCS_FLAG="-max-funcs" +fi + +OPTIMIZED_BINARY=$(mktemp -t -u --suffix=.bolt $(basename ${INPUT_BINARY}).XXX) +OUTPUT_FILE="${OPTIMIZED_BINARY}.out" +BOLT_LOG=$(mktemp -t -u --suffix=.log boltXXX) + +if [[ -z $OFFLINE ]]; then + echo "Verify input binary passes" + echo " INPUT_BINARY: $PRE_COMMAND && $TIMEOUT_OR_CMD $INPUT_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE" + ($PRE_COMMAND && $TIMEOUT_OR_CMD $INPUT_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE) + STATUS=$? + if [[ "$IGNORE_ERROR" == "1" ]]; then + FAIL=0 + else + FAIL=$STATUS + fi + if [[ -e "$GOLD_FILE" ]] ; then + cmp -s "$OUTPUT_FILE" "$GOLD_FILE" + FAIL=$? + fi + if [[ $FAIL -ne "0" ]] ; then + echo " Warning: input binary failed" + else + echo " Input binary passes." + fi +fi + +echo "Verify optimized binary fails" +($BOLT $BOLT_OPTIONS $INPUT_BINARY -o $OPTIMIZED_BINARY >& $BOLT_LOG) +FAIL=$? +if [[ $FAIL -eq "0" ]]; then + if [[ -z $OFFLINE ]]; then + echo " OPTIMIZED_BINARY: $PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE" + ($PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE) + STATUS=$? + if [[ "$IGNORE_ERROR" == "1" ]]; then + FAIL=0 + else + FAIL=$STATUS + fi + if [[ -e "$GOLD_FILE" ]] ; then + cmp -s "$OUTPUT_FILE" "$GOLD_FILE" + FAIL=$? + fi + else + echo "Did it pass? Type the return code [0 = pass, 1 = fail]" + read -n1 PASS + fi + if [[ $FAIL -eq "0" ]] ; then + echo " Warning: optimized binary passes." + else + echo " Optimized binary fails as expected." + fi +else + echo " Bolt crashes while generating optimized binary." +fi + +# Collect function names +FF=$(mktemp -t -u --suffix=.txt func-names.XXX) +nm --defined-only -p $INPUT_BINARY | grep " [TtWw] " | cut -d ' ' -f 3 | egrep -v "\._" | egrep -v '^$' | sort -u > $FF + +# Use function names or numbers +if [[ -z "$MAX_FUNCS" ]] ; then + # Do binary search on function names + if [[ -n "$FUNC_NAMES" ]]; then + FF=$FUNC_NAMES + fi + NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1) + HALF=$(expr \( $NUM_FUNCS + 1 \) / 2) + PREFIX=$(mktemp -t -u --suffix=.txt func-names.XXX) + FF0=$PREFIX\aa + FF1=$PREFIX\ab + split -a 2 -l $HALF $FF $PREFIX + FF=$FF0 + NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1) + CONTINUE=$(expr $NUM_FUNCS \> 0) +else + P=0 + if [[ "$MAX_FUNCS" -eq "0" ]]; then + Q=$(wc -l $FF | cut -d ' ' -f 1) + else + Q=$MAX_FUNCS + fi + I=$Q + CONTINUE=$(expr \( $Q - $P \) \> 1) +fi + +ITER=0 +while [[ "$CONTINUE" -ne "0" ]] ; do + rm -f $OPTIMIZED_BINARY + if [[ -z "$MAX_FUNCS" ]] ; then + echo "Iteration $ITER, trying $FF / $HALF functions" + SEARCH_OPT="-funcs-file-no-regex=$FF" + else + I=$(expr \( $Q + $P \) / 2) + echo "Iteration $ITER, P=$P, Q=$Q, I=$I" + SEARCH_OPT="$MAX_FUNCS_FLAG=$I" + fi + echo " BOLT: $BOLT $BOLT_OPTIONS $INPUT_BINARY $SEARCH_OPT -o $OPTIMIZED_BINARY >& $BOLT_LOG" + ($BOLT $BOLT_OPTIONS $INPUT_BINARY $SEARCH_OPT -o $OPTIMIZED_BINARY >& $BOLT_LOG) + FAIL=$? + echo " BOLT failure=$FAIL" + rm -f $OUTPUT_FILE + if [[ $FAIL -eq "0" ]] ; then + if [[ -z $OFFLINE ]]; then + echo " OPTIMIZED_BINARY: $PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE" + ($PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE) + STATUS=$? + if [[ "$IGNORE_ERROR" == "1" ]]; then + FAIL=0 + else + FAIL=$STATUS + fi + if [[ -e "$GOLD_FILE" ]] ; then + cmp -s "$OUTPUT_FILE" "$GOLD_FILE" + FAIL=$? + fi + echo " OPTIMIZED_BINARY failure=$FAIL" + else + echo "Did it pass? Type the return code [0 = pass, 1 = fail]" + read -n1 PASS + fi + else + FAIL=1 + fi + + if [[ -z "$MAX_FUNCS" ]] ; then + if [[ $FAIL -eq "0" ]] ; then + if [[ "$FF" == "$FF1" ]]; then + NUM_FUNCS=0 + break; + fi + FF=$FF1 + NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1) + else + HALF=$(expr \( $NUM_FUNCS + 1 \) / 2) + PREFIX=$(mktemp -t -u --suffix=.txt func-names.XXX) + split -a 2 -l $HALF $FF $PREFIX + FF0=$PREFIX\aa + FF1=$PREFIX\ab + FF=$FF0 + NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1) + if [[ $NUM_FUNCS -eq "1" && ! -e $FF1 ]]; then + break; + fi + fi + CONTINUE=$(expr $NUM_FUNCS \> 0) + else + if [[ $FAIL -eq "0" ]] ; then + P=$I + else + Q=$I + fi + FF=$I + HALF=$I + CONTINUE=$(expr \( $Q - $P \) \> 1) + fi + ITER=$(expr $ITER + 1) +done + +if [[ -z "$MAX_FUNCS" ]] ; then + if [[ "$NUM_FUNCS" -ne "0" ]] ; then + FAILED="The function(s) that failed are in $FF" + fi +else + if [[ $P -ne $Q ]] ; then + FF=$(grep "processing ending" $BOLT_LOG | sed -e "s/BOLT-INFO: processing ending on \(.*\)/\1/g" | tail -1) + FAILED="The item that failed is $FF @ $Q" + fi +fi + +if [[ -n "$FAILED" ]] ; then + echo "$FAILED" + echo "To reproduce, run: $BOLT $BOLT_OPTIONS $INPUT_BINARY $SEARCH_OPT -o $OPTIMIZED_BINARY" +else + echo "Unable to reproduce bug." +fi + +rm $OPTIMIZED_BINARY $OUTPUT_FILE $BOLT_LOG |