summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/oneshot_gdb.sh
blob: 9161ee4964d3e08557d2c032b9468958a43b77a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/bin/sh
# oneshot_gdb.sh <pid> - catch the client's USERSPACE spin (state R and
# /proc/<pid>/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"