无论如何使用gdb来分析由pyinstaller二进制文件创建的核心转储?我将python / C ++文件打包成一个二进制文件,gdb无法读取python或二进制文件中的符号。
我尝试过只接收来自gdb的问号。
gdb $(which python) -c core
gdb my_binary -c core
答案 0 :(得分:1)
将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
命令一起使用的核心文件来自尝试在pyinstaller
上使用build_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。此外,为build_id
二进制文件报告的构建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恰好匹配(在分布式{{1之间)从源代码构建的那个)。如果不需要使用剥离的引导加载程序,则可能更容易删除run
文件,但这可能比单独加载调试符号更有用。
run
包含每个包含的引导加载程序的调试符号可能是有意义的(据我所知,它确实如此,我还没有找到它们,但我还是怀疑它)。如果您希望gdb使用pyinstaller
的调试符号,其中一部分可能涉及安装单独的包。在我的Debian系统上,包是libc
。我简要介绍了使用调试符号构建pyinstaller引导加载程序,但我还没有完成对libc6-dbg
的解密。
答案 1 :(得分:1)
同时修复: https://github.com/pyinstaller/pyinstaller/pull/2178/files
最近,引导程序也被重新编译并提交给了repo,所以它现在应该可以工作。