3

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

当一个程序崩溃时,它会生成一个核心文件,我可以用它来用 gdb 调试它。但是,如果有人出现在我身后并“有帮助”地重新编译程序并打开额外的调试,或者升级包,或者以任何方式弄乱系统,那么该核心文件将变得无用。

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

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

4

3 回答 3

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
于 2014-09-10T06:59:40.063 回答
0

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

于 2012-07-05T21:14:10.453 回答
0

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

  1. 将系统配置为以二进制文件命名核心,然后将二进制文件安装在脚本可以从中获取它们的标准位置。核心命名说明在此处,另请参阅 core(5)。

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

  3. 补充技巧是在字符串输出中查找“_=/your/binary/here”——“_”是一些 shell/WM/应用程序为它们正在调用的二进制文件设置的特殊环境变量。不过,它也可能会产生误导(例如,当 make 调用您的二进制文件时,它将是 /usr/bin/make)。

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

  1. 再次从核心输出字符串以获取 LD_PRELOAD 和 LD_LIBRARY_PATH 的值。这些会影响二进制文件实际链接的库。
  2. 在二进制文件上运行“ldd”,将这些变量设置为相同的值,然后在“=>”上拆分以查找每个库的文件名。

然后将其全部复制到一个目录并在其上运行 tar 。将日志文件复制到目录中通常也很有帮助。

于 2012-10-01T02:26:06.227 回答