python - pyinstaller 二进制文件的核心转储

标签 python gdb pyinstaller

有没有办法使用 gdb 来分析 pyinstaller 二进制文件创建的核心转储?我将 python/C++ 文件打包到一个二进制文件中,但 gdb 无法从 python 或二进制文件中读取符号。

我已经尝试过,但只收到来自 gdb 的问号。

gdb $(which python) -c core 
gdb my_binary -c core  

最佳答案

将 python 二进制文件与 pyinstaller 生成的二进制文件中的核心文件一起使用是不正确的。 file 的输出命令将确认这一点:

core: ELF 64-bit LSB core file x86-64, version 1 (SYSV), SVR4-style, from './build_id/build/build_id/build_id', 

(为了简洁起见,我省略了该输出行的末尾)。

与之一起使用的核心文件 file命令来自尝试使用 pyinstallerbuild_id.py ,因此出现了名称 build_id在路径名内。

假设my_binary代表您尝试使用 pyinstaller 的结果,它是与该尝试中的核心文件一起使用的正确二进制文件。我已将核心文件中的构建 ID 与所有映射文件进行了比较,它们都匹配。这是对我的 build_id.py 的详细调用的输出在我的核心文件上:

0000000000400000 63116679c3030438046175bc610d21cbd50fbac0 /home/eirik/git/pyinstaller/build_id/build/build_id/build_id
00007f042f80d000 377b0152081112c82460680fe99ec01aa090cd81 /lib/x86_64-linux-gnu/libc-2.24.so
00007f042fbab000 adcc4a5e27d5de8f0bc3c6021b50ba2c35ec9a8e /lib/x86_64-linux-gnu/libz.so.1.2.8
00007f042fdc6000 4e43c23036c6bfd2d4dab183e458e29d87234adc /lib/x86_64-linux-gnu/libdl-2.24.so
00007f042ffca000 a731640ef1cd73c1d727c2a9521b10cafec33c15 /lib/x86_64-linux-gnu/ld-2.24.so

file 的输出这些路径名之一上的命令会报告在该文件的输出行中看到的相同构建 ID。此外,报告的构建 ID 为我的 build_id二进制文件与 pyinstaller 提供的以下文件的构建 ID 匹配:

PyInstaller/bootloader/Linux-64bit/run

看来pyinstaller使用objcopy使用 run 构建二进制文件文件作为前缀。除了报告该 run 的构建 ID 之外文件,file命令还告诉我它已被删除,这与我从 gdb 获得的回溯一致:

Core was generated by `./build_id/build/build_id/build_id'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  strlen () at ../sysdeps/x86_64/strlen.S:106
106 ../sysdeps/x86_64/strlen.S: No such file or directory.
(gdb) backtrace
#0  strlen () at ../sysdeps/x86_64/strlen.S:106
#1  0x00007f042f8424d9 in __add_to_environ (name=0x405da8 "LD_LIBRARY_PATH_ORIG", value=0x0, combined=0x0, replace=1) at setenv.c:131
#2  0x0000000000404688 in ?? ()
#3  0x0000000000402db3 in ?? ()
#4  0x00007f042f82d2b1 in __libc_start_main (main=0x401950, argc=1, argv=0x7fffc57143c8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
    stack_end=0x7fffc57143b8) at ../csu/libc-start.c:291
#5  0x000000000040197e in ?? ()
(gdb) x/i $pc
=> 0x7f042f88d496 <strlen+38>:      movdqu (%rax),%xmm4
(gdb) i r rax
rax            0x0  0
(gdb) 

引导加载程序(run 文件)中的某些内容正在调用 __add_to_environ (可能通过 setenv ,它有一个 jmpq__add_to_environ ),然后将空指针传递给 strlen (推测空指针源自 run )。所有出现的 ??该回溯来自 run文件(它们的地址均以 0x00000000004 开头)。

如果我使用 LD_LIBRARY_PATH=/tmp 运行二进制文件,我不再得到核心转储,所以我猜测空指针是 getenv("LD_LIBRARY_PATH") 的返回值。另外,我在 bootloader/src/pyi_utils.c 中看到了这一点(在 set_dynamic_library_path 中):

    orig_path = pyi_getenv(env_var);
    pyi_setenv(env_var_orig, orig_path);

除了依赖 libc 中的调试符号之外,理解此类崩溃的最大希望是,可能是从源代码构建引导加载程序(run 文件),并保留其调试符号并将其加载到 gdb 中,在从该引导加载程序构建的可执行文件及其核心文件上调用。在这种情况下,重要的是使用从源代码构建的引导加载程序,而不是使用 pyinstaller 分发的引导加载程序。 (都使用 gdb,并构建二进制文件),除非构建 ID 恰好匹配(在分布式 run 和从源代码构建的 ID 之间)。如果不需要使用剥离的引导加载程序,则不剥离 run 可能会更容易。文件,但这可能比单独加载调试符号需要更多工作。

这对于 pyinstaller 可能有意义包含每个包含的引导加载程序的调试符号(据我所知,它确实做到了这一点,我只是还没有找到它们,但我对此表示怀疑)。如果您希望 gdb 使用 libc 的调试符号,其中一部分可能涉及安装单独的软件包。在我的 Debian 系统上,该软件包是 libc6-dbg 。我简要研究了使用调试符号构建 pyinstaller 引导加载程序,但我还没有完成破译 waf还没有。

关于python - pyinstaller 二进制文件的核心转储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38909028/

相关文章:

python - 从 python 调用 gnuplot

c++ - gdb 如何打印 vector<bool> 值

c++ - 列出gdb中类的所有功能

python - Pyinstaller:当我使用 pyinstaller 创建 .exe 文件时,使用 python 中的内置函数打开的可执行文件将在 1 秒后关闭

python - 无法将类型 'Timestamp' 与类型 'int' 进行比较

python - 我正在 Windows 10 计算机上的 python 上使用 openpyxl 库,并尝试使用空格加载 load_workbook

python - 出现操作系统错误 python 库未找到

python - 无法在 PyCharm 中安装任何包

python - 使用与系统默认版本不同的 virtualenv 或 Python 运行 mod_wsgi

compiler-construction - 符号表存储在哪里?