一 背景
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)