Monday, February 5, 2024

[SOLVED] How to bundle a core file with its associated executables?

Issue

How can I bundle a core file with its associated executables and shared libraries?

When a program crashes, it generates a core file, that I can use to debug it with gdb. But if someone comes along behind me and "helpfully" recompiles the program with extra debugging turned on, or upgrades a package, or in any way messes with the system, that core file becomes useless.

So what I'd like is a way to bundle the core dump file with all of the other binaries that it references, into one big file.

Then, of course, I also need a way to open this file in gdb. I don't want to have to "extract" the files back to their original location and overwrite upgraded or changed binaries. I'm imagining a shell script that extracts the binaries to a temp directory and then tells gdb to look there.


Solution

gdb already has the information that you wanted (info sharedlib):

$ gdb -ex 'set height 0' -ex 'set confirm off' \
  -ex 'file /path/to/exe' -ex 'core-file core.pid' \
  -ex 'info sharedlib' -ex quit 

So naturally you can ask gdb to give you this list, and from there you can create a "gdb-bundle" tarball that contains the executable and all the shared libraries that gdb reported.

I wrote a script to automate this:

#!/bin/sh
me=$(basename $0)

usage() {
    echo "Usage:
  $me -p <pid>
  $me <executable> <core>

DESCRIPTION
  $me - Creates a tarball containing the executable, it's core dump and
        all the shared libraries that gdb said it loads.

OPTIONS
    -p <pid>  A running process id of a process to be bundled.
    -h        Show this help message"
}

pid=
while getopts hp: opt
do
    case "$opt" in
        p)
            pid="$OPTARG"
            ;;
        h)
            usage
            exit
            ;;
        \?)
            echo Unknown option
            exit
            ;;
    esac
done
shift $(($OPTIND -1))
executable=$1
corename=$2

if [ -n "$pid" ]; then
    test "$pid" -gt 0 || { echo "pid must be numeric"; exit 1; }
    proc=/proc/$pid/exe
    executable=`readlink -e $proc` ||
        { echo "Could not readlink $proc"; exit 1; }
    corename=${basename}.$pid.core
else
    test -z "$executable" && usage && exit 1;
    test -z "$corename" && usage && exit 1;
fi

basename=$(basename $executable)
if [ -n "$pid" ]; then
    sharedlibs=$(gdb -ex "attach $pid" -ex 'set height 0' \
        -ex 'set confirm off' -ex "generate-core-file $corename" \
        -ex 'info sharedlib' -ex quit|
        sed -n '/Shared Object Library/,/^(/p'|grep -E '(Yes|No)'|
        sed -e 's,[^/]\+,,') || exit 1
    dir="gdb-${basename}.$pid.$(date +%F-%H%M%S)"
else
    sharedlibs=$(gdb -ex 'set height 0' -ex 'set confirm off' \
        -ex "file $executable" -ex "core-file $corename" \
        -ex 'info sharedlib' -ex quit|
        sed -n '/Shared Object Library/,/^(/p'|grep -E '(Yes|No)'|
        sed -e 's,[^/]\+,,') || exit 1
    dir="gdb-${basename}.$(date +%F-%H%M%S)"
fi

mkdir "$dir" && cp "$corename" "$dir" &&
tar chf - $sharedlibs $executable|tar -C $dir -xf - &&
echo -e "gdb:\n\tgdb -ex 'set solib-absolute-prefix ./'" \
    "-ex 'file .$executable' -ex 'core-file ./$corename' " \
    > $dir/makefile &&
echo tar czf $dir.tar.gz $dir &&
tar czf $dir.tar.gz $dir


Answered By - holygeek
Answer Checked By - Mildred Charles (WPSolving Admin)