#!/bin/sh # oneshot_gdb.sh - catch the client's USERSPACE spin (state R and # /proc//syscall == "running"; a kernel busy-wait shows its syscall # number). Fires gdb ONCE, dumps all threads, detaches, CONTs. PID="$1" LOG=/tmp/gdbbt.log : > "$LOG" cir=0 win=0 # count of user-running samples since start samples=0 while kill -0 "$PID" 2>/dev/null; do samples=$((samples+1)) st=$(awk '{print $3}' /proc/$PID/stat 2>/dev/null) sy=$(cat /proc/$PID/syscall 2>/dev/null) if [ "$st" = "R" ] && [ "$sy" = "running" ]; then cir=$((cir+1)); win=$((win+1)) else cir=0 fi if [ "$cir" -ge 4 ] || { [ "$samples" -ge 32 ] && [ "$win" -ge 12 ]; }; then { echo "=== TRIGGER $(date +%T.%3N) pid=$PID cir=$cir win=$win samples=$samples ===" for t in /proc/$PID/task/*; do echo "--- thread $(basename $t): $(awk '{print $3}' $t/stat 2>/dev/null) $(cat $t/comm 2>/dev/null) syscall=$(cat $t/syscall 2>/dev/null | cut -d' ' -f1-2)" done grep -E "libcuda|nvidia" /proc/$PID/maps | head -4 } >> "$LOG" timeout 90 gdb -p "$PID" -batch \ -ex "set pagination off" -ex "set height 0" -ex "set confirm off" \ -ex "info threads" \ -ex "thread apply all bt 12" \ -ex "thread apply all info registers rip rsp rbp rbx rax rdi rsi rdx rcx r8 r9" \ -ex "thread apply all x/10i \$pc" \ >> "$LOG" 2>&1 echo "=== GDB DONE $(date +%T.%3N) ===" >> "$LOG" kill -CONT "$PID" 2>/dev/null exit 0 fi sleep 0.25 done echo "=== process gone after $samples samples ===" >> "$LOG"