zeek/auxil/zeekctl/bin/crash-diag
Patrick Kelley 8fd444092b initial
2025-05-07 15:35:15 -04:00

167 lines
4.4 KiB
Bash
Executable File

#! /usr/bin/env bash
#
# crash-diag [-c] <dir>
#
# -c: if this flag is present, then this script was run from post-terminate
# because Zeek crashed.
# <dir> is the node's working directory.
. `dirname $0`/zeekctl-config.sh
postterminate=0
if [ "$1" = "-c" ]; then
postterminate=1
shift
fi
if [ $# -ne 1 ]; then
echo "crash-diag: wrong number of arguments"
exit 1
fi
if [ ! -d "$1" ]; then
echo "No work dir found"
exit 0
fi
cd "$1"
if [ $? -ne 0 ]; then
exit 1
fi
# Identify all core files in the current directory. We assume these
# filenames contain the word "core" and do not end in ".log".
core=`ls -t *core* 2> /dev/null | grep -v '\.log$'`
# Choose which debugger to use.
gdb_name="gdb"
if [ "${os}" = "Darwin" ]; then
gdb_name="lldb"
elif [ "${os}" = "OpenBSD" ]; then
# The default gdb fails when trying to read Zeek core files.
gdb_name="egdb"
fi
gdb_path=`which $gdb_name 2> /dev/null`
if [ -f "${zeek}" ];then
zeek_version=`"${zeek}" -v 2>/dev/null | awk '{print $3}'`
else
zeek_version="(file not found: ${zeek})"
fi
# If Zeek crashed and if a core file exists, then copy the Zeek binary so that
# the user has the ability to generate a backtrace in the future.
if [ $postterminate -eq 1 ]; then
if [ -n "$core" ]; then
myzeek=${zeek}
if [ "${havenfs}" = "1" ]; then
myzeek=${tmpexecdir}/`basename "${zeek}"`
fi
cp "$myzeek" .
fi
fi
# Output the crash report.
echo
# If no backtrace can be generated, then output an explanation. However,
# skip this if there's no .status file, because in that case Zeek didn't run.
if [ -f .status ]; then
if [ -n "$gdb_path" ]; then
if [ -z "$core" ]; then
# Check if the system allows setting core file size to unlimited,
# because this is what the run-zeek script does when it starts Zeek.
ulimit -c unlimited 2> /dev/null
coresize=`ulimit -c`
if [ "$coresize" != "unlimited" ]; then
echo "No core file found. You may need to change your system settings to"
echo "allow core files."
else
echo "No core file found."
fi
echo
fi
else
if [ -n "$core" ]; then
echo "Unable to output a backtrace because $gdb_name is not installed."
echo "It is recommended to install $gdb_name so that ZeekControl can output a"
echo "backtrace the next time Zeek crashes."
else
echo "No core file found and $gdb_name is not installed. It is recommended to"
echo "install $gdb_name so that ZeekControl can output a backtrace if Zeek crashes."
fi
echo
fi
fi
echo Zeek $zeek_version
uname -sr
echo
zeekplugins=`"${zeek}" -N 2>/dev/null | grep -v "(built-in)"`
if [ -z "$zeekplugins" ]; then
echo "Zeek plugins: (none found)"
else
echo "Zeek plugins:"
echo "$zeekplugins"
fi
# Output a backtrace if we have a debugger and a core file.
if [ -n "$gdb_path" ]; then
if [ -n "$core" ]; then
if [ "$gdb_name" = "gdb" ] || [ "$gdb_name" = "egdb" ]; then
echo "thread apply all bt" >.gdb_cmds
elif [ "$gdb_name" = "lldb" ]; then
echo "bt all" >.gdb_cmds
fi
for c in "$core"; do
if [ -f "$c" ]; then
echo
# Note: zeekctl looks for this string in order to determine
# if a backtrace was output.
echo "Core file: $c"
if [ "$gdb_name" = "gdb" ] || [ "$gdb_name" = "egdb" ]; then
$gdb_path --batch -x .gdb_cmds "${zeek}" "$c" 2>/dev/null
elif [ "$gdb_name" = "lldb" ]; then
$gdb_path --batch -s .gdb_cmds -f "${zeek}" -c "$c" 2>/dev/null
fi
fi
done
rm -f .gdb_cmds
fi
fi
# Usage:
# show_log <filename> <num>
# Output the last <num> lines of <filename>. If <num> is -1, then output the
# entire file.
show_log() {
filename=$1
num=$2
echo
if [ -f $filename ]; then
echo ==== $filename
if [ $num -ge 0 ]; then
tail -$num $filename
else
cat $filename
fi
else
echo ==== No $filename
fi
}
show_log reporter.log 10
show_log stderr.log 10
show_log stdout.log 10
show_log .cmdline 30
show_log .env_vars 30
show_log .status 10
show_log prof.log 10
show_log packet_filter.log 30
show_log loaded_scripts.log -1