#!/bin/bash
# Script to reproduce UdpCommandDemuxer race condition heisenbug
# Runs salmanoff in GDB repeatedly, injecting SIGINT at random intervals
#
# Usage: ./reproduce_heisenbug.sh [WORKING_DIR]
#   WORKING_DIR: Working directory where salmanoff binary and all paths are relative to
#                If not provided, uses WORKING_DIR environment variable, or defaults to project root
#
# Environment variables:
#   WORKING_DIR: Working directory (can be overridden by command-line argument)

# Get the directory where this script is located
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

# Determine working directory (command-line arg > env var > default)
if [ -n "$1" ]; then
    WORKING_DIR="$1"
elif [ -n "$WORKING_DIR" ]; then
    # Use environment variable
    :
else
    # Default to project root
    WORKING_DIR="$PROJECT_ROOT"
fi

# Convert to absolute path
WORKING_DIR="$(cd "$WORKING_DIR" && pwd)"

# Check if working directory exists
if [ ! -d "$WORKING_DIR" ]; then
    echo "Error: Working directory does not exist: $WORKING_DIR" >&2
    exit 1
fi

# Paths - all relative to working directory
SALMANOFF_BINARY="$WORKING_DIR/salmanoff"
GDB_SCRIPT="$SCRIPT_DIR/gdb_heisenbug.gdb"
DELL_LAPTOP_ARGS_INC="$SCRIPT_DIR/../dell_laptop_salmanoff_args.inc.sh"

# Check if binary exists
if [ ! -f "$SALMANOFF_BINARY" ]; then
    echo "Error: salmanoff binary not found at $SALMANOFF_BINARY" >&2
    echo "Working directory: $WORKING_DIR" >&2
    exit 1
fi

# Check if GDB script exists
if [ ! -f "$GDB_SCRIPT" ]; then
    echo "Error: GDB script not found at $GDB_SCRIPT" >&2
    exit 1
fi

if [ ! -f "$DELL_LAPTOP_ARGS_INC" ]; then
    echo "Error: dell-laptop salmanoff args not found at $DELL_LAPTOP_ARGS_INC" >&2
    exit 1
fi

# shellcheck source=../dell_laptop_salmanoff_args.inc.sh
. "$DELL_LAPTOP_ARGS_INC"
SALMANOFF_ARGS=( "${DELL_LAPTOP_SALMANOFF_ARGS[@]}" )

echo "=== UdpCommandDemuxer Heisenbug Reproduction Script ==="
echo "Working Directory: $WORKING_DIR"
echo "Binary: $SALMANOFF_BINARY"
echo "GDB Script: $GDB_SCRIPT"
echo "Arguments: ${SALMANOFF_ARGS[*]}"
echo ""
echo "Press Ctrl+C to stop the loop"
echo ""

# Change to working directory so all relative paths are resolved correctly
cd "$WORKING_DIR"

# Loop counter
ITERATION=0

# Main loop
while true; do
    ITERATION=$((ITERATION + 1))
    echo "=========================================="
    echo "Iteration $ITERATION - $(date)"
    echo "=========================================="
    echo ""

    # Run GDB with the command file
    # GDB will stay interactive on segfault, exit on normal completion
    # When GDB stays interactive (on segfault), this will wait for user to quit GDB
    # When GDB exits normally (program completed), exit code will be 0 and loop continues
    # Note: We use a relative path to salmanoff binary since we're already in WORKING_DIR
    SALMANOFF_RELATIVE="salmanoff"
    if gdb -x "$GDB_SCRIPT" --args "$SALMANOFF_RELATIVE" "${SALMANOFF_ARGS[@]}"; then
        # GDB exited successfully (program completed normally)
        EXIT_CODE=0
    else
        # GDB exited with error (unexpected exit or user interrupted)
        EXIT_CODE=$?
        echo ""
        echo "GDB exited with code $EXIT_CODE"
        if [ $EXIT_CODE -ne 0 ] && [ $EXIT_CODE -ne 130 ]; then
            # Exit code 130 is SIGINT (user pressed Ctrl+C), which is expected
            echo "Unexpected GDB exit - check output above"
        fi
    fi

    echo ""
    echo "Iteration $ITERATION complete. Starting next iteration in 1 second..."
    sleep 1
    echo ""
done

echo ""
echo "Loop terminated."

