mudlet/CI/send_debug_files_to_sentry.sh
Mike Conley 1778238fd6
Fix: Windows crash reports now show the actual cause (#9370)
#### Brief overview of PR changes/additions

When Mudlet crashes on Windows, it sends a crash report to Sentry. Until
now those reports were unusable: instead of showing where in Mudlet the
problem happened, they only listed anonymous system files. This PR fixes
the Windows build so each crash report points at the actual place in
Mudlet that crashed.

#### Motivation for adding to Mudlet

Every recent Windows crash in Sentry was a dead end — we could see that
Mudlet crashed, but not *where*, so none of them could be investigated
or fixed. The crash details we were uploading didn't match the version
of Mudlet people were actually running, so Sentry could never line them
up. This makes Windows crash reports actionable again.

#### Other info (issues closed, discussion etc)

Needs to be verified on a nightly/tagged CI build: the uploaded debug
file should match the shipped `mudlet.exe`, and a fresh crash should
show Mudlet function names. No change for users beyond more useful crash
reports; the new debug file is only sent to Sentry, never shipped.
2026-07-14 12:28:46 +00:00

182 lines
7.4 KiB
Bash

#!/bin/bash
###########################################################################
# Copyright (C) 2025 by Nicolas Keita - nicolaskeita2@gmail.com #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the #
# Free Software Foundation, Inc., #
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
###########################################################################
set -e
SENTRY_CLI_VERSION="3.6.0"
download_sentry_cli() {
local os="$1"
local arch="$2"
local file="$3"
local url=""
local base="https://github.com/getsentry/sentry-cli/releases/download/${SENTRY_CLI_VERSION}"
if [[ "$os" == "Darwin" ]]; then
if [[ "$arch" == "x86_64" ]]; then
url="${base}/sentry-cli-Darwin-x86_64"
elif [[ "$arch" == "arm64" ]]; then
url="${base}/sentry-cli-Darwin-arm64"
fi
elif [[ "$os" == "Linux" ]]; then
if [[ "$arch" == "x86_64" ]]; then
url="${base}/sentry-cli-Linux-x86_64"
fi
elif [[ "$os" == "MINGW"* || "$os" == "MSYS"* || "$os" == "CYGWIN"* ]]; then
if [[ "$arch" == "x86_64" ]]; then
url="${base}/sentry-cli-Windows-x86_64.exe"
elif [[ "$arch" == "i686" || "$arch" == "i386" ]]; then
url="${base}/sentry-cli-Windows-i686.exe"
fi
fi
if [[ -z "$url" ]]; then
echo "Unsupported OS/ARCH: $os / $arch"
return 1
fi
echo "Downloading $url ..."
curl -L -o "$file" "$url"
if [[ "$os" != "MINGW"* && "$os" != "MSYS"* && "$os" != "CYGWIN"* ]]; then
chmod +x "$file"
fi
echo "$file ready"
}
if [ -z "$SENTRY_AUTH_TOKEN" ]; then
echo "[Sentry_upload_debug_files] Missing environment variable: SENTRY_AUTH_TOKEN. Therefore, the debug file upload to sentry.io is canceled."
exit 0
fi
if [ -z "$1" ]; then
echo "Usage: $0 <path-to-mudlet-executable>"
echo "Please provide the path to the Mudlet executable as an argument."
exit 1
fi
MUDLET_EXEC="$(realpath "$1")"
if [ ! -f "$MUDLET_EXEC" ]; then
echo "Error: Mudlet executable not found at $MUDLET_EXEC"
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OS="$(uname -s)"
ARCH="$(uname -m)"
download_sentry_cli "$OS" "$ARCH" "sentry-cli"
./sentry-cli login --auth-token "$SENTRY_AUTH_TOKEN"
FILES_TO_UPLOAD=("$MUDLET_EXEC")
if [[ "$OS" == "Linux" ]]; then
DEBUG_FILE="${MUDLET_EXEC}.debug"
[[ -f "$DEBUG_FILE" ]] && FILES_TO_UPLOAD+=("$DEBUG_FILE")
elif [[ "$OS" == "Darwin" ]]; then
DEBUG_FILE="${MUDLET_EXEC}.dSYM"
[[ -d "$DEBUG_FILE" ]] && FILES_TO_UPLOAD+=("$DEBUG_FILE")
elif [[ "$OS" == "MINGW"* ]]; then
# The PDB shares its debug-id with the shipped mudlet.exe, so uploading both
# lets Sentry match crash minidumps and symbolicate them (see WithSentry.cmake).
# The PDB is expected on every Windows sentry build, so fail loudly if it is
# missing rather than silently uploading only the exe (which would revert to
# unsymbolicated crash reports if the --pdb link flag is ever lost).
PDB_FILE="${MUDLET_EXEC%.exe}.pdb"
if [[ -f "$PDB_FILE" ]]; then
FILES_TO_UPLOAD+=("$PDB_FILE")
else
echo "error: expected PDB at $PDB_FILE not found - Windows crash reports would be unsymbolicated"
exit 1
fi
fi
for f in "${FILES_TO_UPLOAD[@]}"; do
echo "Uploading $f to Sentry..."
./sentry-cli debug-files upload "$f" --project "mudlet"
done
# Qt ships its debug info as separate DWARF ".debug" companions; sentry-cli 3.5.0+
# parses these, so upload them too. See https://github.com/getsentry/sentry/issues/104738
if [[ -n "$MSYSTEM" && -n "$MSYSTEM_PREFIX" ]]; then
MINGW_BIN="${MSYSTEM_PREFIX}/bin"
QT_PLUGINS_DIR="${MSYSTEM_PREFIX}/share/qt6/plugins"
echo ""
echo "=== Collecting Qt DWARF debug companions for Sentry ==="
DEBUG_FILES=()
# Upload .debug companions only for the Qt6 modules mudlet.exe actually depends
# on (walk its import table), not every Qt6 DLL in the bin.
if command -v objdump >/dev/null 2>&1; then
declare -A seen_dll=()
pending=("$MUDLET_EXEC")
# Runtime-loaded Qt plugins can pull in Qt modules that mudlet.exe does not
# link directly (e.g. the svg imageformat/iconengine plugins pull in Qt6Svg,
# which is not in our components list). Seed the walk with the plugin DLLs too
# so their imports get their .debug companions collected as well.
if [[ -d "$QT_PLUGINS_DIR" ]]; then
while IFS= read -r -d '' plugin_dll; do
pending+=("$plugin_dll")
done < <(find "$QT_PLUGINS_DIR" -type f -name '*.dll' -print0)
fi
while [[ ${#pending[@]} -gt 0 ]]; do
current="${pending[0]}"
pending=("${pending[@]:1}")
while IFS= read -r dll; do
[[ -z "$dll" || -n "${seen_dll[$dll]:-}" ]] && continue
seen_dll[$dll]=1
dll_path="$MINGW_BIN/$dll"
[[ -f "$dll_path" ]] || continue
pending+=("$dll_path")
if [[ "$dll" == Qt6*.dll ]]; then
# companion may be "<name>.dll.debug" or "<name>.debug"; add once
for debug_file in "$MINGW_BIN/${dll}.debug" "$MINGW_BIN/${dll%.dll}.debug"; do
[[ -f "$debug_file" && -z "${seen_dll[$debug_file]:-}" ]] && { seen_dll[$debug_file]=1; DEBUG_FILES+=("$debug_file"); }
done
fi
done < <(objdump -p "$current" 2>/dev/null | sed -n 's/^[[:space:]]*DLL Name:[[:space:]]*//p')
done
else
echo "objdump not found - falling back to uploading all Qt6 debug companions"
for debug_file in "$MINGW_BIN"/Qt6*.debug; do
[[ -f "$debug_file" ]] && DEBUG_FILES+=("$debug_file")
done
fi
# Qt plugins (image formats, platforms, tls, ...) can appear in crash stack
# traces too, so upload every plugin companion we can find
if [[ -d "$QT_PLUGINS_DIR" ]]; then
while IFS= read -r -d '' debug_file; do
DEBUG_FILES+=("$debug_file")
done < <(find "$QT_PLUGINS_DIR" -type f -name '*.debug' -print0)
fi
if [[ ${#DEBUG_FILES[@]} -gt 0 ]]; then
echo "Uploading ${#DEBUG_FILES[@]} Qt debug companion files to Sentry..."
./sentry-cli debug-files upload "${DEBUG_FILES[@]}" --project "mudlet"
echo "Qt debug symbols uploaded successfully"
else
echo "No Qt .debug files found - are the qt6-*-debug packages installed?"
fi
fi
rm -f sentry-cli