| #!/bin/sh | 
 | # | 
 | # american fuzzy lop++ - status check tool | 
 | # ---------------------------------------- | 
 | # | 
 | # Originally written by Michal Zalewski | 
 | # | 
 | # Copyright 2015 Google Inc. All rights reserved. | 
 | # Copyright 2019-2020 AFLplusplus Project. All rights reserved. | 
 | # | 
 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
 | # you may not use this file except in compliance with the License. | 
 | # You may obtain a copy of the License at: | 
 | # | 
 | #   http://www.apache.org/licenses/LICENSE-2.0 | 
 | # | 
 | # This tool summarizes the status of any locally-running synchronized | 
 | # instances of afl-fuzz. | 
 | # | 
 |  | 
 | echo "$0 status check tool for afl-fuzz by Michal Zalewski" | 
 | echo | 
 | test "$1" = "-h" && { | 
 |   echo $0 [-s] output_directory | 
 |   echo | 
 |   echo Options: | 
 |   echo   -s  -  skip details and output summary results only | 
 |   echo | 
 |   exit 1 | 
 | } | 
 |  | 
 | if [ "$1" = "-s" ]; then | 
 |  | 
 |   SUMMARY_ONLY=1 | 
 |   DIR="$2" | 
 |  | 
 | else | 
 |  | 
 |   unset SUMMARY_ONLY | 
 |   DIR="$1" | 
 |  | 
 | fi | 
 |  | 
 | if [ "$DIR" = "" ]; then | 
 |  | 
 |   echo "Usage: $0 [ -s ] afl_sync_dir" 1>&2 | 
 |   echo 1>&2 | 
 |   echo "The -s option causes the tool to skip all the per-fuzzer trivia and show" 1>&2 | 
 |   echo "just the summary results. See docs/parallel_fuzzing.md for additional tips." 1>&2 | 
 |   echo 1>&2 | 
 |   exit 1 | 
 |  | 
 | fi | 
 |  | 
 | cd "$DIR" || exit 1 | 
 |  | 
 | if [ -d queue ]; then | 
 |  | 
 |   echo "[-] Error: parameter is an individual output directory, not a sync dir." 1>&2 | 
 |   exit 1 | 
 |  | 
 | fi | 
 |  | 
 | RED=`tput setaf 9 1 1` | 
 | GREEN=`tput setaf 2 1 1` | 
 | BLUE=`tput setaf 4 1 1` | 
 | YELLOW=`tput setaf 11 1 1` | 
 | NC=`tput sgr0` | 
 | RESET="$NC" | 
 |  | 
 | CUR_TIME=`date +%s` | 
 |  | 
 | TMP=`mktemp -t .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || TMP=`mktemp -p /data/local/tmp .afl-whatsup-XXXXXXXX` || exit 1 | 
 |  | 
 | ALIVE_CNT=0 | 
 | DEAD_CNT=0 | 
 |  | 
 | TOTAL_TIME=0 | 
 | TOTAL_EXECS=0 | 
 | TOTAL_EPS=0 | 
 | TOTAL_CRASHES=0 | 
 | TOTAL_PFAV=0 | 
 | TOTAL_PENDING=0 | 
 |  | 
 | # Time since last path / crash / hang, formatted as string | 
 | FMT_TIME="0 days 0 hours" | 
 | FMT_PATH="${RED}none seen yet${NC}" | 
 | FMT_CRASH="none seen yet" | 
 | FMT_HANG="none seen yet" | 
 |  | 
 | if [ "$SUMMARY_ONLY" = "" ]; then | 
 |  | 
 |   echo "Individual fuzzers" | 
 |   echo "==================" | 
 |   echo | 
 |  | 
 | fi | 
 |  | 
 | fmt_duration() | 
 | { | 
 |   DUR_STRING= | 
 |   if [ $1 -eq 0 ]; then | 
 |     return 1 | 
 |   fi | 
 |  | 
 |   local duration=$((CUR_TIME - $1)) | 
 |   local days=$((duration / 60 / 60 / 24)) | 
 |   local hours=$(((duration / 60 / 60) % 24)) | 
 |   local minutes=$(((duration / 60) % 60)) | 
 |   local seconds=$((duration % 60)) | 
 |  | 
 |   if [ $days -gt 0 ]; then | 
 |     DUR_STRING="$days days, $hours hours" | 
 |   elif [ $hours -gt 0 ]; then | 
 |     DUR_STRING="$hours hours, $minutes minutes" | 
 |   elif [ $minutes -gt 0 ]; then | 
 |     DUR_STRING="$minutes minutes, $seconds seconds" | 
 |   else | 
 |     DUR_STRING="$seconds seconds" | 
 |   fi | 
 | } | 
 |  | 
 | FIRST=true | 
 | TOTAL_WCOP= | 
 | TOTAL_LAST_PATH=0 | 
 |  | 
 | for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do | 
 |  | 
 |   sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP" | 
 |   . "$TMP" | 
 |  | 
 |   RUN_UNIX=$((CUR_TIME - start_time)) | 
 |   RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24)) | 
 |   RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24)) | 
 |  | 
 |   test -n "$cycles_wo_finds" && { | 
 |     test -z "$FIRST" && TOTAL_WCOP="${TOTAL_WCOP}/" | 
 |     TOTAL_WCOP="${TOTAL_WCOP}${cycles_wo_finds}" | 
 |     FIRST= | 
 |   } | 
 |  | 
 |   if [ "$SUMMARY_ONLY" = "" ]; then | 
 |  | 
 |     echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<" | 
 |     echo | 
 |  | 
 |   fi | 
 |  | 
 |   if ! kill -0 "$fuzzer_pid" 2>/dev/null; then | 
 |  | 
 |     if [ "$SUMMARY_ONLY" = "" ]; then | 
 |  | 
 |       echo "  Instance is dead or running remotely, skipping." | 
 |       echo | 
 |  | 
 |     fi | 
 |  | 
 |     DEAD_CNT=$((DEAD_CNT + 1)) | 
 |     continue | 
 |  | 
 |   fi | 
 |  | 
 |   ALIVE_CNT=$((ALIVE_CNT + 1)) | 
 |  | 
 |   EXEC_SEC=$((execs_done / RUN_UNIX)) | 
 |   PATH_PERC=$((cur_path * 100 / paths_total)) | 
 |  | 
 |   TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX)) | 
 |   TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC)) | 
 |   TOTAL_EXECS=$((TOTAL_EXECS + execs_done)) | 
 |   TOTAL_CRASHES=$((TOTAL_CRASHES + unique_crashes)) | 
 |   TOTAL_PENDING=$((TOTAL_PENDING + pending_total)) | 
 |   TOTAL_PFAV=$((TOTAL_PFAV + pending_favs)) | 
 |  | 
 |   if [ "$last_path" -gt "$TOTAL_LAST_PATH" ]; then | 
 |     TOTAL_LAST_PATH=$last_path | 
 |   fi | 
 |  | 
 |   if [ "$SUMMARY_ONLY" = "" ]; then | 
 |  | 
 |     # Warnings in red | 
 |     TIMEOUT_PERC=$((exec_timeout * 100 / execs_done)) | 
 |     if [ $TIMEOUT_PERC -ge 10 ]; then | 
 |       echo "  ${RED}timeout_ratio $TIMEOUT_PERC%${NC}" | 
 |     fi | 
 |  | 
 |     if [ $EXEC_SEC -lt 100 ]; then | 
 |       echo "  ${RED}slow execution, $EXEC_SEC execs/sec${NC}" | 
 |     fi | 
 |  | 
 |     fmt_duration $last_path && FMT_PATH=$DUR_STRING | 
 |     fmt_duration $last_crash && FMT_CRASH=$DUR_STRING | 
 |     fmt_duration $last_hang && FMT_HANG=$DUR_STRING | 
 |     FMT_CWOP="not available" | 
 |     test -n "$cycles_wo_finds" && { | 
 |       test "$cycles_wo_finds" = 0 && FMT_CWOP="$cycles_wo_finds" | 
 |       test "$cycles_wo_finds" -gt 10 && FMT_CWOP="${YELLOW}$cycles_wo_finds${NC}" | 
 |       test "$cycles_wo_finds" -gt 50 && FMT_CWOP="${RED}$cycles_wo_finds${NC}" | 
 |     } | 
 |  | 
 |     echo "  last_path       : $FMT_PATH" | 
 |     echo "  last_crash      : $FMT_CRASH" | 
 |     echo "  last_hang       : $FMT_HANG" | 
 |     echo "  cycles_wo_finds : $FMT_CWOP" | 
 |  | 
 |     CPU_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $3}') | 
 |     MEM_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $4}') | 
 |  | 
 |     echo "  cpu usage $CPU_USAGE%, memory usage $MEM_USAGE%" | 
 |     echo "  cycle $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, path $cur_path/$paths_total (${PATH_PERC}%)" | 
 |  | 
 |     if [ "$unique_crashes" = "0" ]; then | 
 |       echo "  pending $pending_favs/$pending_total, coverage $bitmap_cvg, no crashes yet" | 
 |     else | 
 |       echo "  pending $pending_favs/$pending_total, coverage $bitmap_cvg, crash count $unique_crashes (!)" | 
 |     fi | 
 |  | 
 |     echo | 
 |  | 
 |   fi | 
 |  | 
 | done | 
 |  | 
 | # Formatting for total time, time since last path, crash, and hang | 
 | fmt_duration $((CUR_TIME - TOTAL_TIME)) && FMT_TIME=$DUR_STRING | 
 | # Formatting for total execution | 
 | FMT_EXECS="0 millions" | 
 | EXECS_MILLION=$((TOTAL_EXECS / 1000 / 1000)) | 
 | EXECS_THOUSAND=$((TOTAL_EXECS / 1000 % 1000)) | 
 | if [ $EXECS_MILLION -gt 9 ]; then | 
 |   FMT_EXECS="$EXECS_MILLION millions" | 
 | elif [ $EXECS_MILLION -gt 0 ]; then | 
 |   FMT_EXECS="$EXECS_MILLION millions, $EXECS_THOUSAND thousands" | 
 | else | 
 |   FMT_EXECS="$EXECS_THOUSAND thousands" | 
 | fi | 
 |  | 
 | rm -f "$TMP" | 
 |  | 
 | TOTAL_DAYS=$((TOTAL_TIME / 60 / 60 / 24)) | 
 | TOTAL_HRS=$(((TOTAL_TIME / 60 / 60) % 24)) | 
 |  | 
 | test -z "$TOTAL_WCOP" && TOTAL_WCOP="not available" | 
 | fmt_duration $TOTAL_LAST_PATH && TOTAL_LAST_PATH=$DUR_STRING | 
 |  | 
 | test "$TOTAL_TIME" = "0" && TOTAL_TIME=1 | 
 |  | 
 | echo "Summary stats" | 
 | echo "=============" | 
 | echo | 
 | echo "       Fuzzers alive : $ALIVE_CNT" | 
 |  | 
 | if [ ! "$DEAD_CNT" = "0" ]; then | 
 |   echo "      Dead or remote : $DEAD_CNT (excluded from stats)" | 
 | fi | 
 |  | 
 | echo "      Total run time : $FMT_TIME" | 
 | echo "         Total execs : $FMT_EXECS" | 
 | echo "    Cumulative speed : $TOTAL_EPS execs/sec" | 
 | if [ "$ALIVE_CNT" -gt "0" ]; then | 
 |   echo "       Average speed : $((TOTAL_EPS / ALIVE_CNT)) execs/sec" | 
 | fi | 
 | echo "       Pending paths : $TOTAL_PFAV faves, $TOTAL_PENDING total" | 
 |  | 
 | if [ "$ALIVE_CNT" -gt "1" ]; then | 
 |   echo "  Pending per fuzzer : $((TOTAL_PFAV/ALIVE_CNT)) faves, $((TOTAL_PENDING/ALIVE_CNT)) total (on average)" | 
 | fi | 
 |  | 
 | echo "       Crashes found : $TOTAL_CRASHES locally unique" | 
 | echo "Cycles without finds : $TOTAL_WCOP" | 
 | echo "  Time without finds : $TOTAL_LAST_PATH" | 
 | echo | 
 |  | 
 | exit 0 |