Files

148 lines
4.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# 核心配置
CRASH_LOG_DIR="./crash_logs"
RUN_DURATION=2
GDB_TIMEOUT=$((RUN_DURATION + 2)) # 延长超时,确保GDB完全初始化
MAX_LOOP=0
# 强制捕获所有致命信号
CRASH_SIGNALS=("SIGSEGV" "SIGABRT" "SIGILL" "SIGFPE" "SIGBUS")
# 创建日志目录
mkdir -p ${CRASH_LOG_DIR}
rm -f ${CRASH_LOG_DIR}/* # 清空旧日志(可选)
# 清理进程函数
cleanup() {
pkill -9 gdb >/dev/null 2>&1
pkill -9 pPowerManger >/dev/null 2>&1
sleep 0.2
}
# 检查是否是真崩溃(从日志+系统日志双重验证)
is_real_crash() {
local log_file=$1
local loop=$2
# 1. 检查GDB日志中的崩溃关键字
if grep -qiE "segmentation fault|sigsegv|crash detected|backtrace" "${log_file}"; then
return 0
fi
# 2. 检查系统dmesg中的段错误记录(终极验证)
if dmesg | grep -i "pPowerManger.*segfault" | grep -i "loop_${loop}"; then
return 0
fi
return 1
}
# 打印系统级崩溃日志(dmesg)
print_system_crash_log() {
local loop=$1
echo -e "\033[33m===== 系统级崩溃日志(dmesg)=====\033[0m"
dmesg | grep -A 5 -B 2 "pPowerManger.*segfault" | tail -10
echo -e "\033[33m===================================\033[0m"
}
echo -e "🔍 启动pPowerManger稳定性测试(强制捕获段错误)\n"
echo "📂 崩溃日志目录: ${CRASH_LOG_DIR}"
echo "⏱ 程序运行时长: ${RUN_DURATION}秒"
echo "📌 捕获信号: ${CRASH_SIGNALS[*]}"
echo -e "========================================\n"
cleanup # 初始清理
LOOP_COUNT=0
while true; do
LOOP_COUNT=$((LOOP_COUNT + 1))
if [ ${MAX_LOOP} -ne 0 ] && [ ${LOOP_COUNT} -gt ${MAX_LOOP} ]; then
echo -e "\n✅ 测试完成(${MAX_LOOP}次循环无崩溃)"
cleanup
exit 0
fi
echo -e "===== 第 ${LOOP_COUNT} 次循环 ====="
CRASH_LOG="${CRASH_LOG_DIR}/crash_loop_${LOOP_COUNT}.log"
GDB_CMD="${CRASH_LOG_DIR}/gdb_cmds_${LOOP_COUNT}.gdb"
# 生成强化版GDB脚本:强制捕获所有信号,优先初始化信号处理
cat > ${GDB_CMD} << EOF
# 核心:GDB启动后先设置信号捕获,再启动程序
set args pPowerManger.moos
set timeout ${GDB_TIMEOUT}
set print pretty on
set print frame-arguments all
set logging file ${CRASH_LOG}.gdb_raw
set logging on # 开启GDB原始日志(双重保障)
# 强制捕获所有致命信号
EOF
# 为每个崩溃信号添加捕获规则(追加到GDB脚本)
for sig in "${CRASH_SIGNALS[@]}"; do
cat >> ${GDB_CMD} << EOF
handle ${sig} stop print pass nostop # 即使子线程崩溃也捕获
EOF
done
# 追加程序启动和崩溃处理逻辑
cat >> ${GDB_CMD} << EOF
# 延迟10ms启动程序,确保GDB完全初始化
sleep 0.01
run
# 崩溃后强制打印所有信息(无论是否主线程)
if \$exitcode != 0 || \$signal_number != 0
echo "\n====================================="
echo " CRASH DETECTED"
echo "====================================="
echo "Loop: ${LOOP_COUNT}"
echo "Exit code: \$exitcode"
echo "Signal: \$signal_name (\$signal_number)"
echo "====================================="
thread apply all bt full # 打印所有线程的调用栈(关键!)
info threads
info proc mappings # 打印内存映射(排查内存越界)
info locals
info registers
endif
set logging off
quit
EOF
# 核心:用nohup+GDB启动,避免输出丢失;同时记录进程ID
echo "启动程序(GDB强化模式)..."
nohup timeout ${GDB_TIMEOUT} gdb -batch -x ${GDB_CMD} ./pPowerManger > ${CRASH_LOG} 2>&1 &
GDB_PID=$!
wait ${GDB_PID} # 等待GDB执行完成
# 双重验证:检查是否真崩溃
if is_real_crash ${CRASH_LOG} ${LOOP_COUNT}; then
# 捕获到真崩溃
echo -e "\033[31m❌ 第 ${LOOP_COUNT} 次循环捕获到段错误!\033[0m"
echo -e "\033[31m📄 崩溃日志: ${CRASH_LOG}\033[0m"
print_system_crash_log ${LOOP_COUNT}
# 打印最关键的调用栈(所有线程)
echo -e "\033[31m===== 所有线程崩溃调用栈 =====\033[0m"
grep -A 50 "thread apply all bt full" ${CRASH_LOG} | grep -v "No stack frame"
echo -e "\033[31m==============================\033[0m"
cleanup
echo -e "\n🛑 测试终止,完整日志在 ${CRASH_LOG}"
exit 1
else
# 无崩溃(正常退出/启动失败)
if grep -qi "Program exited normally" ${CRASH_LOG}; then
echo "✅ 程序正常运行${RUN_DURATION}秒后退出"
else
echo "⚠️ 程序启动失败(非段错误),继续循环"
# 保留启动失败日志(方便排查)
mv ${CRASH_LOG} ${CRASH_LOG}.start_fail
fi
rm -f ${GDB_CMD} ${CRASH_LOG}.gdb_raw
fi
cleanup
echo -e "第 ${LOOP_COUNT} 次循环完成\n"
sleep 0.5
done