Add a script to parse backtraces
authorBernd Schubert <bschubert@ddn.com>
Mon, 29 Jul 2024 19:57:56 +0000 (21:57 +0200)
committerBernd Schubert <bernd.schubert@fastmail.fm>
Mon, 29 Jul 2024 22:16:55 +0000 (00:16 +0200)
util/parse-backtrace.sh [new file with mode: 0755]

diff --git a/util/parse-backtrace.sh b/util/parse-backtrace.sh
new file mode 100755 (executable)
index 0000000..adf706d
--- /dev/null
@@ -0,0 +1,114 @@
+#!/bin/bash
+
+tmpfile=`mktemp backtrace.XXX`
+
+PROGRAM_PATH=''
+TRACE_TYPE=glibc
+
+print_help()
+{
+    echo "Usage: "
+    echo "   " `basename $0`" [-s] [-p <path/to/filename>] -t <\"full trace\">"
+    echo "Options: "
+    echo "    -t   '<trace>'  - The entire trace should be put into quotes"
+    echo "                      for this option"
+    echo "    -p   path/to/filename  - optional path to the binary, typically"
+    echo "                            autodetected"
+    echo
+    exit 1
+}
+
+if [ -z "$1" -o "$1" = "-h" -o "$1" = "--help" ]; then
+    rm -f $tmpfile
+    print_help
+fi
+
+while getopts "hf:t:" opt; do
+    case $opt in
+    h)
+        print_help
+        ;;
+    f)
+        PROGRAM_PATH="$OPTARG"
+        ;;
+    t)
+        TRACE="$OPTARG"
+        ;;
+    *)
+        print_help
+        ;;
+        esac
+done
+
+
+# use addr2line
+parse_glibc_trace()
+{
+    local trace="$1"
+    local filename="$2"
+    local tmpname=""
+    local symbol=""
+
+    IFS=$'\n'
+    for line in ${trace}; do
+
+        #echo "Line: '$line"
+
+        # remove C2 A0 (non breaking space, as inserted by windows)
+        line=$(echo $line | sed 's/\xC2\xA0/ /g')
+
+        line=`echo $line | egrep "\[" | egrep "\]"`
+        [ -n "$line" ] || continue
+
+        # cut off additional syslog part - beginning of line to ':'
+        line=$(echo $line line | sed -e 's/.*://')
+
+        # parse lines like
+        # /usr/lib/libfuse3.so.3(+0x1c0ef) [0x7fca6061c0ef]
+
+        filename=$(echo $line | awk '{print $1}' | sed -e 's/(.*$//')
+        if [ -z "${filename}" ]; then
+            echo "Failed to get filename path for line: \"$line\""
+            return
+        fi
+
+        if [[ $filename != /* ]]; then
+            if [ -n "${PROGRAM_PATH}" ]; then
+                filename="${PROGRAM_PATH}"
+            else
+                tmpname="$(which $filename)"
+                if [ $? -ne 0 ]; then
+                    echo "Failed to get path for '$filename'"
+                    continue
+                fi
+                filename="${tmpname}"
+            fi
+        fi
+
+        # for plain glibc backtrace_symbols the symbol is also in column1,
+        # within the brackets ()
+        symbol=$(echo $line | awk '{print $1}' | sed -e 's/^.*(//' | sed -e 's/).*//')
+        if [ -z "${symbol}" ]; then
+            echo "Failed to get symbol for line: \"$line\""
+            continue
+        fi
+
+        addr2line -a -p -s -C -f -i -e ${filename} ${symbol}
+    done
+}
+
+if [ -z "$TRACE" ]; then
+    echo "Missing backtrace option!"
+    echo
+    print_help
+fi
+
+
+# For now only glibc backtrace_symbols traces are supported
+if [ $TRACE_TYPE = "glibc" ]; then
+    parse_glibc_trace "$TRACE" "${PROGRAM_PATH}"
+else
+    echo "Unknown tracetype: '${TRACE_TYPE}'"
+fi
+
+rm -f $tmpfile