Search code examples
linuxdebugginggdbcoredump

How to bundle a core file with its associated executables?


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