brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · d5ce059 Raw
267 lines · bash
1#!/bin/bash2##===- bolt/utils/bughunter.sh - Help locate BOLT bugs -------*- Script -*-===##3#4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5# See https://llvm.org/LICENSE.txt for license information.6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7# details.8#9##===----------------------------------------------------------------------===##10#11# This script attempts to narrow down llvm-bolt bug to a single function in the12# input binary.13#14# If such a function is found, llvm-bolt could be run just on this function15# to mitigate debugging process.16#17# The following envvars are used by this script:18#19#   BOLT              - path to llvm-bolt20#21#   BOLT_OPTIONS      - options to be used by llvm-bolt22#23#   INPUT_BINARY      - input for llvm-bolt24#25#   PRE_COMMAND       - command to execute prior to running optimized binary26#27#   POST_COMMAND      - command to filter results of running optimized binary28#29#   TIMEOUT_OR_CMD    - optional timeout or command on optimized binary command30#                       if the value is a number with an optional trailing letter31#                       [smhd] it is considered a parameter to "timeout",32#                       otherwise it's a shell command that wraps the optimized33#                       binary command.34#35#   COMMAND_LINE      - command line options to run optimized binary with36#37#   IGNORE_ERROR      - ignore error codes returned from optimized binary38#39#   GOLD_FILE         - file containing expected output from optimized binary40#41#   FUNC_NAMES        - if set, path to an initial list of function names to42#                       search.  Otherwise, nm is used on the original binary.43#44#   OFFLINE           - if set, bughunter will produce the binaries but will not45#                       run them, and will depend on you telling whether it46#                       succeeded or not.47#48#   MAX_FUNCS         - if set, use -max-funcs to narrow down the offending49#                       function.  if non-zero, start -max-funcs at $MAX_FUNCS50#                       otherwise, count the number of symbols in the binary.51#52#   MAX_FUNCS_FLAG    - BOLT command line option to use for MAX_FUNCS search.53#                       Default is -max-funcs.  Can also be used for relocation54#                       debugging, e.g. -max-data-relocations.55#56#   VERBOSE           - if non-empty, set the script to echo mode.57#58##===----------------------------------------------------------------------===##59 60BOLT=${BOLT:=llvm-bolt}61 62ulimit -c 063set -o pipefail64 65if [[ -n "$VERBOSE" ]]; then66    set -x67fi68 69if [[ ! -x $INPUT_BINARY ]] ; then70    echo "INPUT_BINARY must be set to an executable file"71    exit 172fi73 74if [[ -z "$PRE_COMMAND" ]] ; then75    PRE_COMMAND=':'76fi77 78if [[ -z "$POST_COMMAND" ]] ; then79    POST_COMMAND='cat'80fi81 82if [[ -n "$TIMEOUT_OR_CMD" && $TIMEOUT_OR_CMD =~ ^[0-9]+[smhd]?$ ]] ; then83    TIMEOUT_OR_CMD="timeout -s KILL $TIMEOUT_OR_CMD"84fi85 86if [[ -z "$MAX_FUNCS_FLAG" ]] ; then87    MAX_FUNCS_FLAG="-max-funcs"88fi89 90OPTIMIZED_BINARY=$(mktemp -t -u --suffix=.bolt $(basename ${INPUT_BINARY}).XXX)91OUTPUT_FILE="${OPTIMIZED_BINARY}.out"92BOLT_LOG=$(mktemp -t -u --suffix=.log boltXXX)93 94if [[ -z $OFFLINE ]]; then95    echo "Verify input binary passes"96    echo "  INPUT_BINARY: $PRE_COMMAND && $TIMEOUT_OR_CMD $INPUT_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE"97    ($PRE_COMMAND && $TIMEOUT_OR_CMD $INPUT_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE)98    STATUS=$?99    if [[ "$IGNORE_ERROR" == "1" ]]; then100        FAIL=0101    else102        FAIL=$STATUS103    fi104    if [[ -e "$GOLD_FILE" ]] ; then105        cmp -s "$OUTPUT_FILE" "$GOLD_FILE"106        FAIL=$?107    fi108    if [[ $FAIL -ne "0" ]] ; then109        echo "  Warning: input binary failed"110    else111        echo "  Input binary passes."112    fi113fi114 115echo "Verify optimized binary fails"116($BOLT $BOLT_OPTIONS $INPUT_BINARY -o $OPTIMIZED_BINARY >& $BOLT_LOG)117FAIL=$?118if [[ $FAIL -eq "0" ]]; then119    if [[ -z $OFFLINE ]]; then120        echo "  OPTIMIZED_BINARY: $PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE"121        ($PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE)122        STATUS=$?123        if [[ "$IGNORE_ERROR" == "1" ]]; then124            FAIL=0125        else126            FAIL=$STATUS127        fi128        if [[ -e "$GOLD_FILE" ]] ; then129            cmp -s "$OUTPUT_FILE" "$GOLD_FILE"130            FAIL=$?131        fi132    else133        echo "Did it pass? Type the return code [0 = pass, 1 = fail]"134        read -n1 FAIL135    fi136    if [[ $FAIL -eq "0" ]] ; then137        echo "  Warning: optimized binary passes."138    else139        echo "  Optimized binary fails as expected."140    fi141else142    echo "  Bolt crashes while generating optimized binary."143fi144 145# Collect function names146FF=$(mktemp -t -u --suffix=.txt func-names.XXX)147nm --defined-only -p $INPUT_BINARY | grep " [TtWw] " | cut -d ' ' -f 3 | egrep -v "\._" | egrep -v '^$' | sort -u > $FF148 149# Use function names or numbers150if [[ -z "$MAX_FUNCS" ]] ; then151    # Do binary search on function names152    if [[ -n "$FUNC_NAMES" ]]; then153        FF=$FUNC_NAMES154    fi155    NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1)156    HALF=$(expr \( $NUM_FUNCS + 1 \) / 2)157    PREFIX=$(mktemp -t -u --suffix=.txt func-names.XXX)158    FF0=$PREFIX\aa159    FF1=$PREFIX\ab160    split -a 2 -l $HALF $FF $PREFIX161    FF=$FF0162    NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1)163    CONTINUE=$(expr $NUM_FUNCS \> 0)164else165    P=0166    if [[ "$MAX_FUNCS" -eq "0" ]]; then167        Q=$(wc -l $FF | cut -d ' ' -f 1)168    else169        Q=$MAX_FUNCS170    fi171    I=$Q172    CONTINUE=$(expr \( $Q - $P \) \> 1)173fi174 175ITER=0176while [[ "$CONTINUE" -ne "0" ]] ; do177    rm -f $OPTIMIZED_BINARY178    if [[ -z "$MAX_FUNCS" ]] ; then179        echo "Iteration $ITER, trying $FF / $HALF functions"180        SEARCH_OPT="-funcs-file-no-regex=$FF"181    else182        I=$(expr \( $Q + $P \) / 2)183        echo "Iteration $ITER, P=$P, Q=$Q, I=$I"184        SEARCH_OPT="$MAX_FUNCS_FLAG=$I"185    fi186    echo "  BOLT: $BOLT $BOLT_OPTIONS $INPUT_BINARY $SEARCH_OPT -o $OPTIMIZED_BINARY >& $BOLT_LOG"187    ($BOLT $BOLT_OPTIONS $INPUT_BINARY $SEARCH_OPT -o $OPTIMIZED_BINARY >& $BOLT_LOG)188    FAIL=$?189    echo "  BOLT failure=$FAIL"190    rm -f $OUTPUT_FILE191    if [[ $FAIL -eq "0" ]] ; then192        if [[ -z $OFFLINE ]]; then193            echo "  OPTIMIZED_BINARY: $PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE"194            ($PRE_COMMAND && $TIMEOUT_OR_CMD $OPTIMIZED_BINARY $COMMAND_LINE |& $POST_COMMAND >& $OUTPUT_FILE)195            STATUS=$?196            if [[ "$IGNORE_ERROR" == "1" ]]; then197                FAIL=0198            else199                FAIL=$STATUS200            fi201            if [[ -e "$GOLD_FILE" ]] ; then202                cmp -s "$OUTPUT_FILE" "$GOLD_FILE"203                FAIL=$?204            fi205            echo "  OPTIMIZED_BINARY failure=$FAIL"206        else207            echo "Did it pass? Type the return code [0 = pass, 1 = fail]"208            read -n1 FAIL209        fi210    else211        FAIL=1212    fi213 214    if [[ -z "$MAX_FUNCS" ]] ; then215        if [[ $FAIL -eq "0" ]] ; then216            if [[ "$FF" == "$FF1" ]]; then217                NUM_FUNCS=0218                break;219            fi220            FF=$FF1221            NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1)222        else223            HALF=$(expr \( $NUM_FUNCS + 1 \) / 2)224            PREFIX=$(mktemp -t -u --suffix=.txt func-names.XXX)225            split -a 2 -l $HALF $FF $PREFIX226            FF0=$PREFIX\aa227            FF1=$PREFIX\ab228            FF=$FF0229            NUM_FUNCS=$(wc -l $FF | cut -d ' ' -f 1)230            if [[ $NUM_FUNCS -eq "1" && ! -e $FF1 ]]; then231                break;232            fi233        fi234        CONTINUE=$(expr $NUM_FUNCS \> 0)235    else236        if [[ $FAIL -eq "0" ]] ; then237            P=$I238        else239            Q=$I240        fi241        FF=$I242        HALF=$I243        CONTINUE=$(expr \( $Q - $P \) \> 1)244    fi245    ITER=$(expr $ITER + 1)246done247 248if [[ -z "$MAX_FUNCS" ]] ; then249    if [[ "$NUM_FUNCS" -ne "0" ]] ; then250        FAILED="The function(s) that failed are in $FF"251    fi252else253    if [[ $P -ne $Q ]] ; then254        FF=$(grep "processing ending" $BOLT_LOG | sed -e "s/BOLT-INFO: processing ending on \(.*\)/\1/g" | tail -1)255        FAILED="The item that failed is $FF @ $Q"256    fi257fi258 259if [[ -n "$FAILED" ]] ; then260    echo "$FAILED"261    echo "To reproduce, run: $BOLT $BOLT_OPTIONS $INPUT_BINARY $SEARCH_OPT -o $OPTIMIZED_BINARY"262else263    echo "Unable to reproduce bug."264fi265 266rm $OPTIMIZED_BINARY $OUTPUT_FILE $BOLT_LOG267