如何将核心文件与其关联的可执行文件捆绑在一起?

时间:2012-06-20 04:32:06

标签: linux debugging gdb core

如何将核心文件与其关联的可执行文件和共享库捆绑在一起?

当程序崩溃时,它会生成一个核心文件,我可以使用它来使用gdb对其进行调试。但是,如果有人跟在我身后并且“帮助”重新编译程序,打开额外的调试,或升级程序包,或以任何方式混淆系统,那核心文件就变得无用了。

所以我想要的是将核心文件与它引用的所有其他二进制文件捆绑在一个大文件中的方法。

然后,当然,我还需要一种方法在gdb中打开这个文件。我不想将文件“提取”回原始位置并覆盖升级或更改的二进制文件。我想象一个shell脚本将二进制文件提取到临时目录,然后告诉gdb看那里。

3 个答案:

答案 0 :(得分:2)

gdb已经拥有您想要的信息(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 

很自然地,您可以请求gdb为您提供此列表,然后您可以创建一个“gdb-bundle”tarball,其中包含可执行文件和gdb报告的所有共享库。

我写了一个脚本来自动执行此操作:

#!/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

答案 1 :(得分:0)

您可以捕获SIGSEGV,然后编写子进程以将相关的进程文件(使用lsof)复制到临时目录中。

答案 2 :(得分:0)

首先找到与核心相关的二进制文件。您有几个选择:

  1. 将系统配置为在导致它们的二进制文件之后命名核心,并将二进制文件安装在脚本可以从中获取的标准位置。命名核心are here的说明,也见核心(5)。

  2. 如果您无法配置系统,我提出的最好的方法是在核心上运行字符串,然后为每个字符串运行“file”上的有效路径,并为“ELF”进行操作“和”可执行文件“。这可能会给你错误的答案,特别是如果二进制文件被另一个实用程序(如make)调用它们可能出现在核心中,那么你可以添加其他过滤器,如排除/ bin和/ usr / bin中的路径,如果你知道的话你的二进制文件总是说/ opt,并选择具有最新mtime的二进制文件(更新的软件更可能是核心的,更可能是你的,而不是系统附带的软件)。

  3. 补充技巧是在字符串输出中查找“_ = / your / binary / here” - “_”是一个特殊的环境变量,由某些shell / WMs / apps设置为二进制文件重新调用。它也可能会产生误导(例如,当make调用你的二进制文件时,它将是/ usr / bin / make。)

  4. 其次,收集二进制文件的依赖项:

    1. 再次从核心输出字符串输出LD_PRELOAD和LD_LIBRARY_PATH的值。这些可能会影响二进制文件实际链接的库。
    2. 在二进制文件上运行“ldd”,将这些变量设置为相同的值,并在“=&gt;”上拆分找到每个库的文件名。
    3. 然后将其全部复制到目录中并在其上运行tar。将日志文件复制到目录中通常也很有帮助。