• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2#
3# american fuzzy lop++ - status check tool
4# ----------------------------------------
5#
6# Originally written by Michal Zalewski
7#
8# Copyright 2015 Google Inc. All rights reserved.
9# Copyright 2019-2022 AFLplusplus Project. All rights reserved.
10#
11# Licensed under the Apache License, Version 2.0 (the "License");
12# you may not use this file except in compliance with the License.
13# You may obtain a copy of the License at:
14#
15#   https://www.apache.org/licenses/LICENSE-2.0
16#
17# This tool summarizes the status of any locally-running synchronized
18# instances of afl-fuzz.
19#
20
21echo "$0 status check tool for afl-fuzz by Michal Zalewski"
22echo
23test "$1" = "-h" -o "$1" = "-hh" && {
24  echo "Usage: $0 [-s] [-d] afl_output_directory"
25  echo
26  echo Options:
27  echo "  -s  -  skip details and output summary results only"
28  echo "  -d  -  include dead fuzzer stats"
29  echo
30  exit 1
31}
32
33unset SUMMARY_ONLY
34unset PROCESS_DEAD
35
36while [ "$1" = "-s" -o "$1" = "-d" ]; do
37
38  if [ "$1" = "-s" ]; then
39    SUMMARY_ONLY=1
40  fi
41
42  if [ "$1" = "-d" ]; then
43    PROCESS_DEAD=1
44  fi
45
46  shift
47
48done
49
50DIR="$1"
51
52if [ "$DIR" = "" ]; then
53
54  echo "Usage: $0 [-s] [-d] afl_output_directory" 1>&2
55  echo 1>&2
56  echo Options: 1>&2
57  echo "  -s  -  skip details and output summary results only" 1>&2
58  echo "  -d  -  include dead fuzzer stats" 1>&2
59  echo 1>&2
60  exit 1
61
62fi
63
64cd "$DIR" || exit 1
65
66if [ -d queue ]; then
67
68  echo "[-] Error: parameter is an individual output directory, not a sync dir." 1>&2
69  exit 1
70
71fi
72
73RED=`tput setaf 9 1 1`
74GREEN=`tput setaf 2 1 1`
75BLUE=`tput setaf 4 1 1`
76YELLOW=`tput setaf 11 1 1`
77NC=`tput sgr0`
78RESET="$NC"
79
80CUR_TIME=`date +%s`
81
82TMP=`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
83
84ALIVE_CNT=0
85DEAD_CNT=0
86
87TOTAL_TIME=0
88TOTAL_EXECS=0
89TOTAL_EPS=0
90TOTAL_CRASHES=0
91TOTAL_PFAV=0
92TOTAL_PENDING=0
93
94# Time since last find / crash / hang, formatted as string
95FMT_TIME="0 days 0 hours"
96FMT_FIND="${RED}none seen yet${NC}"
97FMT_CRASH="none seen yet"
98FMT_HANG="none seen yet"
99
100if [ "$SUMMARY_ONLY" = "" ]; then
101
102  echo "Individual fuzzers"
103  echo "=================="
104  echo
105
106fi
107
108fmt_duration()
109{
110  DUR_STRING=
111  if [ $1 -le 0 ]; then
112    return 1
113  fi
114
115  local duration=$((CUR_TIME - $1))
116  local days=$((duration / 60 / 60 / 24))
117  local hours=$(((duration / 60 / 60) % 24))
118  local minutes=$(((duration / 60) % 60))
119  local seconds=$((duration % 60))
120
121  if [ $duration -le 0 ]; then
122    DUR_STRING="0 seconds"
123  elif [ $duration -eq 1 ]; then
124    DUR_STRING="1 second"
125  elif [ $days -gt 0 ]; then
126    DUR_STRING="$days days, $hours hours"
127  elif [ $hours -gt 0 ]; then
128    DUR_STRING="$hours hours, $minutes minutes"
129  elif [ $minutes -gt 0 ]; then
130    DUR_STRING="$minutes minutes, $seconds seconds"
131  else
132    DUR_STRING="$seconds seconds"
133  fi
134}
135
136FIRST=true
137TOTAL_WCOP=
138TOTAL_LAST_FIND=0
139
140for i in `find . -maxdepth 2 -iname fuzzer_stats | sort`; do
141
142  sed 's/^command_line.*$/_skip:1/;s/[ ]*:[ ]*/="/;s/$/"/' "$i" >"$TMP"
143  . "$TMP"
144
145  RUN_UNIX=$run_time
146  RUN_DAYS=$((RUN_UNIX / 60 / 60 / 24))
147  RUN_HRS=$(((RUN_UNIX / 60 / 60) % 24))
148
149  test -n "$cycles_wo_finds" && {
150    test -z "$FIRST" && TOTAL_WCOP="${TOTAL_WCOP}/"
151    TOTAL_WCOP="${TOTAL_WCOP}${cycles_wo_finds}"
152    FIRST=
153  }
154
155  if [ "$SUMMARY_ONLY" = "" ]; then
156
157    echo ">>> $afl_banner ($RUN_DAYS days, $RUN_HRS hrs) fuzzer PID: $fuzzer_pid <<<"
158    echo
159
160  fi
161
162  if ! kill -0 "$fuzzer_pid" 2>/dev/null; then
163
164    if [ "$SUMMARY_ONLY" = "" ]; then
165
166      echo "  Instance is dead or running remotely, skipping."
167      echo
168
169    fi
170
171    DEAD_CNT=$((DEAD_CNT + 1))
172    last_find=0
173
174    if [ "$PROCESS_DEAD" = "" ]; then
175
176      continue
177
178    fi
179
180  fi
181
182  ALIVE_CNT=$((ALIVE_CNT + 1))
183
184  EXEC_SEC=0
185  test -z "$RUN_UNIX" -o "$RUN_UNIX" = 0 || EXEC_SEC=$((execs_done / RUN_UNIX))
186  PATH_PERC=$((cur_item * 100 / corpus_count))
187
188  TOTAL_TIME=$((TOTAL_TIME + RUN_UNIX))
189  TOTAL_EPS=$((TOTAL_EPS + EXEC_SEC))
190  TOTAL_EXECS=$((TOTAL_EXECS + execs_done))
191  TOTAL_CRASHES=$((TOTAL_CRASHES + saved_crashes))
192  TOTAL_PENDING=$((TOTAL_PENDING + pending_total))
193  TOTAL_PFAV=$((TOTAL_PFAV + pending_favs))
194
195  if [ "$last_find" -gt "$TOTAL_LAST_FIND" ]; then
196    TOTAL_LAST_FIND=$last_find
197  fi
198
199  if [ "$SUMMARY_ONLY" = "" ]; then
200
201    # Warnings in red
202    TIMEOUT_PERC=$((exec_timeout * 100 / execs_done))
203    if [ $TIMEOUT_PERC -ge 10 ]; then
204      echo "  ${RED}timeout_ratio $TIMEOUT_PERC%${NC}"
205    fi
206
207    if [ $EXEC_SEC -eq 0 ]; then
208      echo "  ${YELLOW}no data yet, 0 execs/sec${NC}"
209    elif [ $EXEC_SEC -lt 100 ]; then
210      echo "  ${RED}slow execution, $EXEC_SEC execs/sec${NC}"
211    fi
212
213    fmt_duration $last_find && FMT_FIND=$DUR_STRING
214    fmt_duration $last_crash && FMT_CRASH=$DUR_STRING
215    fmt_duration $last_hang && FMT_HANG=$DUR_STRING
216    FMT_CWOP="not available"
217    test -n "$cycles_wo_finds" && {
218      test "$cycles_wo_finds" = 0 && FMT_CWOP="$cycles_wo_finds"
219      test "$cycles_wo_finds" -gt 10 && FMT_CWOP="${YELLOW}$cycles_wo_finds${NC}"
220      test "$cycles_wo_finds" -gt 50 && FMT_CWOP="${RED}$cycles_wo_finds${NC}"
221    }
222
223    echo "  last_find       : $FMT_FIND"
224    echo "  last_crash      : $FMT_CRASH"
225    echo "  last_hang       : $FMT_HANG"
226    echo "  cycles_wo_finds : $FMT_CWOP"
227
228    CPU_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $3}')
229    MEM_USAGE=$(ps aux | grep $fuzzer_pid | grep -v grep | awk '{print $4}')
230
231    echo "  cpu usage $CPU_USAGE%, memory usage $MEM_USAGE%"
232    echo "  cycles $((cycles_done + 1)), lifetime speed $EXEC_SEC execs/sec, items $cur_item/$corpus_count (${PATH_PERC}%)"
233
234    if [ "$saved_crashes" = "0" ]; then
235      echo "  pending $pending_favs/$pending_total, coverage $bitmap_cvg, no crashes yet"
236    else
237      echo "  pending $pending_favs/$pending_total, coverage $bitmap_cvg, crashes saved $saved_crashes (!)"
238    fi
239
240    echo
241
242  fi
243
244done
245
246# Formatting for total time, time since last find, crash, and hang
247fmt_duration $((CUR_TIME - TOTAL_TIME)) && FMT_TIME=$DUR_STRING
248# Formatting for total execution
249FMT_EXECS="0 millions"
250EXECS_MILLION=$((TOTAL_EXECS / 1000 / 1000))
251EXECS_THOUSAND=$((TOTAL_EXECS / 1000 % 1000))
252if [ $EXECS_MILLION -gt 9 ]; then
253  FMT_EXECS="$EXECS_MILLION millions"
254elif [ $EXECS_MILLION -gt 0 ]; then
255  FMT_EXECS="$EXECS_MILLION millions, $EXECS_THOUSAND thousands"
256else
257  FMT_EXECS="$EXECS_THOUSAND thousands"
258fi
259
260rm -f "$TMP"
261
262TOTAL_DAYS=$((TOTAL_TIME / 60 / 60 / 24))
263TOTAL_HRS=$(((TOTAL_TIME / 60 / 60) % 24))
264
265test -z "$TOTAL_WCOP" && TOTAL_WCOP="not available"
266fmt_duration $TOTAL_LAST_FIND && TOTAL_LAST_FIND=$DUR_STRING
267
268test "$TOTAL_TIME" = "0" && TOTAL_TIME=1
269
270if [ "$PROCESS_DEAD" = "" ]; then
271
272  TXT="excluded from stats"
273
274else
275
276  TXT="included in stats"
277  ALIVE_CNT=$(($ALIVE_CNT - $DEAD_CNT))
278
279fi
280
281echo "Summary stats"
282echo "============="
283echo
284echo "       Fuzzers alive : $ALIVE_CNT"
285
286if [ ! "$DEAD_CNT" = "0" ]; then
287  echo "      Dead or remote : $DEAD_CNT ($TXT)"
288fi
289
290echo "      Total run time : $FMT_TIME"
291echo "         Total execs : $FMT_EXECS"
292echo "    Cumulative speed : $TOTAL_EPS execs/sec"
293if [ "$ALIVE_CNT" -gt "0" ]; then
294  echo "       Average speed : $((TOTAL_EPS / ALIVE_CNT)) execs/sec"
295fi
296echo "       Pending items : $TOTAL_PFAV faves, $TOTAL_PENDING total"
297
298if [ "$ALIVE_CNT" -gt "1" ]; then
299  echo "  Pending per fuzzer : $((TOTAL_PFAV/ALIVE_CNT)) faves, $((TOTAL_PENDING/ALIVE_CNT)) total (on average)"
300fi
301
302echo "       Crashes saved : $TOTAL_CRASHES"
303echo "Cycles without finds : $TOTAL_WCOP"
304echo "  Time without finds : $TOTAL_LAST_FIND"
305echo
306
307exit 0
308