程序core了,调试看到的还是问号

本文探讨了如何在C程序发布时去除调试符号以减小体积,但保留核心功能。通过测试和实例展示了如何在运行时不加载符号表,但在调试时加载符号以获取完整堆栈信息。介绍了删除符号表的方法,以及如何通过符号文件和eu-strip工具提取并导入符号表进行调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 背景

C程序发布的时候,经常去掉-g编译选项的,那么这就遇到一个问题,当程序运行core dump后,想去调试查看core的具体信息,会发现很多符号都被优化掉了,看到的栈信息要么是问号,要么变量无法打印值;去掉符号表,却可以让程序体积更小,而且不容易泄漏程序的信息,更安全些。

这就产生了矛盾,我们在运行的时候不需要符号表,调试的时候需要符号表,那我们能否把符号表在发布程序的时候删除,调试的时候加载符号表信息那,这样就满足了需要。

二 测试程序

2.1 测试源码

为了直观起见,先写个简单的c代码用于演示,代码如下:

1 #include <stdio.h>
  2 
  3 int func()
  4 {
  5     int a = 5;
  6     int b = a*5+8;
  7     int * pi = NULL;
  8     *pi = 0;
  9     printf("In func a is:%d b is:%d",a,b);
 10 }
 11 
 12 int main()
 13 {
 14     int a = func();
 15     printf("%d\n", a);
 16 }

2.2 编译

编译下:

miao@ubuntu-lab:~/c-test$ gcc -o test testdebug.c

gdb调试看看:

root@ubuntu-lab:/home/miao/c-test# gdb ./test -q
Reading symbols from ./test...
(No debugging symbols found in ./test)
(gdb) quit

可以看到显示没有调试符号表信息,我们重新用-g编译选项试试:

root@ubuntu-lab:/home/miao/c-test# gcc -o test-debug -g ./testdebug.c 
root@ubuntu-lab:/home/miao/c-test# ls
test  test-debug  testdebug.c
root@ubuntu-lab:/home/miao/c-test# gdb ./test-debug -q
Reading symbols from ./test-debug...
(gdb)

其实也不是完全没有符号,也还是有不少的,只是没有调试信息,可以用命令查看:

root@ubuntu-lab:/home/miao/c-test# readelf -h ./test|grep "string table index"
  Section header string table index: 30
root@ubuntu-lab:/home/miao/c-test# 
root@ubuntu-lab:/home/miao/c-test# readelf -h ./test-debug|grep "string table index"
  Section header string table index: 36

两个符号表的大小是有差距的差距6个,这个表示符号表的index的个数。查下段表更清晰:

root@ubuntu-lab:/home/miao/c-test# readelf -S ./test-debug|grep '.debug'
  [28] .debug_aranges    PROGBITS         0000000000000000  00003035
  [29] .debug_info       PROGBITS         0000000000000000  00003065
  [30] .debug_abbrev     PROGBITS         0000000000000000  00003159
  [31] .debug_line       PROGBITS         0000000000000000  000031fd
  [32] .debug_str        PROGBITS         0000000000000000  0000326e
  [33] .debug_line_str   PROGBITS         0000000000000000  00003353
root@ubuntu-lab:/home/miao/c-test# 
root@ubuntu-lab:/home/miao/c-test# 
root@ubuntu-lab:/home/miao/c-test# 
root@ubuntu-lab:/home/miao/c-test# readelf -S ./test|grep '.debug'
root@ubuntu-lab:/home/miao/c-test#

2.3 删除符号表

编译的时候可以采用-g编译,然后发布的时候去掉符号表,可以使用命令:strip。如下最简单的处理下:

root@ubuntu-lab:/home/miao/c-test# ll -al ./test*
-rwxrwxr-x 1 miao miao 15984 Apr 30 10:41 ./test*
-rwxr-xr-x 1 root root 17304 Apr 30 10:48 ./test-debug*
-rw-rw-r-- 1 miao miao   171 Apr 30 10:41 ./testdebug.c
root@ubuntu-lab:/home/miao/c-test# strip ./test-debug
root@ubuntu-lab:/home/miao/c-test# ll -al
total 44
drwxrwxr-x  2 miao miao  4096 Apr 30 11:19 ./
drwxr-x--- 16 miao miao  4096 Apr 30 10:41 ../
-rwxrwxr-x  1 miao miao 15984 Apr 30 10:41 test*
-rwxr-xr-x  1 root root 14464 Apr 30 11:19 test-debug*
-rw-rw-r--  1 miao miao   171 Apr 30 10:41 testdebug.c
root@ubuntu-lab:/home/miao/c-test# nm -s test-debug
nm: test-debug: no symbols
root@ubuntu-lab:/home/miao/c-test# nm -s test
000000000000038c r __abi_tag
0000000000004010 B __bss_start
0000000000004010 b completed.0
                 w __cxa_finalize@GLIBC_2.2.5
...

可以看到strip处理过的testdebug,比不用-g 选项的编译出来的test文件更小,通过nm命令验证下,确实任何符号都被删除了,而不用-g编译的文件还可以看到符号信息的。

三 符号表引入测试

3.1  core测试

默认情况下不会产生core文件,加大core文件尺寸:

root@ubuntu-lab:/home/miao/c-test# ulimit -c unlimited
root@ubuntu-lab:/home/miao/c-test# tail -f

重新编译运行:

root@ubuntu-lab:/home/miao/c-test# gcc  -g -o testdebug ./testdebug.c 
root@ubuntu-lab:/home/miao/c-test# strip testdebug -o testdebug-strip

看下core的信息:

root@ubuntu-lab:/home/miao/c-test# tail -f /var/log/apport.log
ERROR: apport (pid 125154) Sat Apr 30 11:52:20 2022: executable: /home/miao/c-test/testdebug-strip (command line "./testdebug-strip")
ERROR: apport (pid 125154) Sat Apr 30 11:52:20 2022: executable does not belong to a package, ignoring
ERROR: apport (pid 125154) Sat Apr 30 11:52:20 2022: writing core dump to core._home_miao_c-test_testdebug-strip.0.3fc6ea16-9440-4d72-81f8-7221d0b6684d.125153.3233349 (limit: -1)

调试下看看:

root@ubuntu-lab:/home/miao/c-test# gdb ./testdebug-strip /var/lib/apport/coredump/core._home_miao_c-test_testdebug-strip.0.3fc6ea16-9440-4d72-81f8-7221d0b6684d.125153.3233349 -q
Reading symbols from ./testdebug-strip...
(No debugging symbols found in ./testdebug-strip)
[New LWP 125153]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./testdebug-strip'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000055d8d93bc178 in ?? ()
(gdb) where
#0  0x000055d8d93bc178 in ?? ()
#1  0x000055d8d93bc1b3 in ?? ()
#2  0x00007f173a2ebfd0 in __libc_start_call_main (main=main@entry=0x55d8d93bc19d, argc=argc@entry=1, argv=argv@entry=0x7ffe16913908) at ../sysdeps/nptl/libc_start_call_main.h:58
#3  0x00007f173a2ec07d in __libc_start_main_impl (main=0x55d8d93bc19d, argc=1, argv=0x7ffe16913908, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffe169138f8)
    at ../csu/libc-start.c:409
#4  0x000055d8d93bc085 in ?? ()
(gdb) bt
#0  0x000055d8d93bc178 in ?? ()
#1  0x000055d8d93bc1b3 in ?? ()
#2  0x00007f173a2ebfd0 in __libc_start_call_main (main=main@entry=0x55d8d93bc19d, argc=argc@entry=1, argv=argv@entry=0x7ffe16913908) at ../sysdeps/nptl/libc_start_call_main.h:58
#3  0x00007f173a2ec07d in __libc_start_main_impl (main=0x55d8d93bc19d, argc=1, argv=0x7ffe16913908, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffe169138f8)
    at ../csu/libc-start.c:409
#4  0x000055d8d93bc085 in ?? ()

因为没有符号信息,很可惜看不到具体的符号信息,也不知道在哪里core了。

(gdb) symbol-file /home/miao/c-test/testdebug
Load new symbol table from "/home/miao/c-test/testdebug"? (y or n) y
Reading symbols from /home/miao/c-test/testdebug...
(gdb) where
#0  0x000055d8d93bc178 in func () at ./testdebug.c:8
#1  0x000055d8d93bc1b3 in main () at ./testdebug.c:14
(gdb)

看重点,加载符号文件,这个是直接加载没有strip前的文件,是包含符号表的。我们清晰的可以看到core的位置是在第8行。

顺便说下,gdb调试多线程,打印多线程堆栈信息命令:thread apply all bt full

3.2 提取符号表

root@ubuntu-lab:/home/miao/c-test# eu-strip testdebug -f testdebug.sym
root@ubuntu-lab:/home/miao/c-test# ll 
total 100
drwxrwxr-x  2 miao miao  4096 Apr 30 12:23 ./
drwxr-x--- 16 miao miao  4096 Apr 30 12:09 ../
-rwxr-xr-x  1 root root 15984 Apr 30 11:23 test*
-rwxr-xr-x  1 root root 14464 Apr 30 11:24 test-debug*
-rwxr-xr-x  1 root root 14568 Apr 30 12:23 testdebug*
-rw-rw-r--  1 miao miao   205 Apr 30 11:38 testdebug.c
-rwxr-xr-x  1 root root 14464 Apr 30 11:52 testdebug-strip*
-rwxr-xr-x  1 root root  5864 Apr 30 12:23 testdebug.sym*
root@ubuntu-lab:/home/miao/c-test# file test.sym
test.sym: cannot open `test.sym' (No such file or directory)
root@ubuntu-lab:/home/miao/c-test# file ./testdebug.sym
./testdebug.sym: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter \004, BuildID[sha1]=5881c326d8f784139407ed0c7576149cb19270f4, for GNU/Linux 3.2.0, with debug_info, not stripped

我们通过命令:eu-strip testdebug -f testdebug.sym提取testdebug中的符号表,保存为文件testdebug.sym。

我们gdb调试的时候导入这个符号试试:

root@ubuntu-lab:/home/miao/c-test# gdb ./testdebug-strip /var/lib/apport/coredump/core._home_miao_c-test_testdebug-strip.0.3fc6ea16-9440-4d72-81f8-7221d0b6684d.125153.3233349 -q
Reading symbols from ./testdebug-strip...
(No debugging symbols found in ./testdebug-strip)
[New LWP 125153]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./testdebug-strip'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x000055d8d93bc178 in ?? ()
(gdb) symbol-file /home/miao/c-test/testdebug.sym
Load new symbol table from "/home/miao/c-test/testdebug.sym"? (y or n) y
Reading symbols from /home/miao/c-test/testdebug.sym...
(gdb) where
#0  0x000055d8d93bc178 in func () at testdebug.c:8
#1  0x000055d8d93bc1b3 in main () at testdebug.c:14
(gdb)

四 参考网站

[https://blog.youkuaiyun.com/bluebubble/article/details/10407217](https://blog.youkuaiyun.com/bluebubble/article/details/10407217)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值