目录
随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有一点用处的技巧,用的不多的技巧可能一个星期就忘了。
想了很久想通过一些手段把这些事情记录下来。也尝试过在书上记笔记,这也只是一时的,书不在手边的时候那些笔记就和没记一样,不是很方便。
很多时候我们遇到了问题,一般情况下都是选择在搜索引擎检索相关内容,这样来的也更快一点,除非真的找不到才会去选择翻书。后来就想到了写博客,博客作为自己的一个笔记平台倒是挺合适的。随时可以查阅,不用随身携带。
同时由于写博客是对外的,既然是对外的就不能随便写,任何人都可以看到。经验对于我来说那就只是经验而已,公布出来说不一定我的一些经验可以帮助到其他的人。遇到和我相同问题时可以少走一些弯路。
既然决定了要写博客,那就只能认真去写。不管写的好不好,尽力就行。千里之行始于足下,一步一个脚印,慢慢来
,写的多了慢慢也会变好的。权当是记录自己的成长的一个过程,等到以后再往回看时,就会发现自己以前原来这么菜😂。
本系列博客所述资料均来自互联网
,并不是本人原创(只有博客是自己写的)。出于热心,本人将自己的所学笔记整理并推出相对应的使用教程,方面其他人学习。为国内的物联网事业发展尽自己的一份绵薄之力,没有为自己谋取私利的想法
。若出现侵权现象,请告知本人,本人会立即停止更新,并删除相应的文章和代码。
实验代码
编写测试代码,这里需要故意写出错误代码,测试CoreDump是否正常工作。
示例代码中因为pStr指向字符串常量,字符串常量是保存在常量区的,调用free释放常量区的内存肯定会导致段错误。
ubuntu@kvm:~/CoreDump$ vim ./TestCoreDump.c
#include "stdio.h"
#include "stdlib.h"
void dumpCrash()
{
char *pStr = "test coredump";
free(pStr);
}
int main()
{
dumpCrash();
return 0;
}
编译
解析core文件需要符号表等debug信息。而且为了更好找到代码位置,最好不要让编译器自动优化。
添加调试信息
这边以GCC编译器作为举例,GCC常用的编译选项如下所示。
root@kvm:~/CoreDump# gcc --help
-E:仅作预处理,不进行编译、汇编和链接
-S:仅编译到汇编语言,不进行汇编和链接
-c:只编译、汇编,不链接
-g/-ggdb:生成调试信息
-I:指定include包含文件的搜索目录
-o:输出成指定文件名
-w:不生成任何警告
-Wall:生成所有的警告
......
本次示例中可以使用下列示例命令完成可执行文件的编译。
root@kvm:~/CoreDump# gcc -ggdb3 -O0 TestCoreDump.c -o TestCoreDump
命令中添加-g或者-ggdb的编译选项。-g产生的debug信息是OS native format,GDB可以使用。而-ggdb产生的debug信息更倾向于给GDB使用。
如果用的GDB调试器,那么使用-ggdb选项。如果是其他调试器,则使用-g。在-ggdb选项后的数字指定了调试信息的级别。在这种情况下,-ggdb33表示生成最详细的调试信息。数字表示调试信息的级别,其中:
- ggdb0: 不包含调试信息。
- ggdb1: 生成基本的调试信息。
- ggdb2: 生成比基本更多的调试信息。
- ggdb3: 生成最详细的调试信息。
禁止编译优化
有些编译器编译会存在一个默认的优化等级,经过优化的代码会与原始代码存在一定的差异。随着优化等级越高,差异越大。这会使得我们的调试变得异常困难。
所以我们在编译是需要使用-O0编译参数将编译过程设置为不进行任何优化。
优化级别 | 说明 | 备注 |
---|---|---|
-O0 | 关闭所有优化 | 代码空间大,运行效率低 |
-O1 | 基本优化等级 | 编译器在不花费太多编译时间基础上,试图生成更快、更小的代码 |
-O2 | O1的升级版 | 编译器试图提高代码性能,而不会增大体积和占用太多编译时间 |
-O3 | 最危险的等级 | 会延长代码编译时间,生成更大体积、更耗内存的二进制文件,大大增加编译失败的几率和不可预知的程序行为,得不偿失 |
-Og | O1的基础上去掉了影响调试的优化 | 如果最终是为了调试程序,可以使用这个参数。不过光有这个参数也是不行的,这个参数只是告诉编译器,编译后的代码不要影响调试,但调试信息的生成还是靠-g参数的 |
-Os | O2的基础上进一步优化代码尺寸 | 去掉了那些会导致最终可执行程序增大的优化,如果想要更小的可执行程序,可选择这个参数。 |
-Ofast | 优化到破坏标准合规性的点 | 在O3的基础上,添加了一些非常规优化,这些优化是通过打破一些国际标准(比如一些数学函数的实现标准)来实现的,所以一般不推荐使用该参数。 |
禁止去除符号
有一些编译脚本会在编译完成后使用strip工具去除目标文件中的一些符号表、调试符号表信息,以减小静态库、动态库和程序的大小。strip后的elf文件不方便调试。我们需要在编译目录中找到中原始的可执行文件。
这里通过file命令可以查看可执行文件的信息,只有提示not stripped
字样的可执行文件才具备调试的功能。
root@kvm:~/CoreDump# file ./TestCoreDump
./TestCoreDump: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6a269357cb09285ddd34db494ab1dadb366ee8a5, not stripped
这里演示一下strip工具的用法,可以看到经过strip工具处理后的可执行文件,file命令查询的结果是stripped。
root@kvm:~/CoreDump# strip TestCoreDump -o TestCoreDump-strip
root@kvm:~/CoreDump# file ./TestCoreDump-strip
./TestCoreDump-strip: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=6a269357cb09285ddd34db494ab1dadb366ee8a5, stripped
运行
执行编译的程序会触发程序崩溃,程序的运行结果中出现了core dumped(核心已转储)
字眼,说明core文件已经生成。
root@kvm:~/CoreDump# ./TestCoreDump
*** Error in `./TestCoreDump': munmap_chunk(): invalid pointer: 0x00000000004005e4 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777f5)[0x7f6a84d217f5]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x1a8)[0x7f6a84d2e6e8]
./TestCoreDump[0x400542]
./TestCoreDump[0x400553]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f6a84cca840]
./TestCoreDump[0x400459]
======= Memory map: ========
00400000-00401000 r-xp 00000000 fc:01 265244 /home/ubuntu/桌面/CoreDump/TestCoreDump
00600000-00601000 r--p 00000000 fc:01 265244 /home/ubuntu/桌面/CoreDump/TestCoreDump
00601000-00602000 rw-p 00001000 fc:01 265244 /home/ubuntu/桌面/CoreDump/TestCoreDump
01f74000-01f95000 rw-p 00000000 00:00 0 [heap]
7f6a84a94000-7f6a84aaa000 r-xp 00000000 fc:01 660680 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6a84aaa000-7f6a84ca9000 ---p 00016000 fc:01 660680 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6a84ca9000-7f6a84caa000 rw-p 00015000 fc:01 660680 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f6a84caa000-7f6a84e6a000 r-xp 00000000 fc:01 660642 /lib/x86_64-linux-gnu/libc-2.23.so
7f6a84e6a000-7f6a8506a000 ---p 001c0000 fc:01 660642 /lib/x86_64-linux-gnu/libc-2.23.so
7f6a8506a000-7f6a8506e000 r--p 001c0000 fc:01 660642 /lib/x86_64-linux-gnu/libc-2.23.so
7f6a8506e000-7f6a85070000 rw-p 001c4000 fc:01 660642 /lib/x86_64-linux-gnu/libc-2.23.so
7f6a85070000-7f6a85074000 rw-p 00000000 00:00 0
7f6a85074000-7f6a8509a000 r-xp 00000000 fc:01 660614 /lib/x86_64-linux-gnu/ld-2.23.so
7f6a85280000-7f6a85283000 rw-p 00000000 00:00 0
7f6a85298000-7f6a85299000 rw-p 00000000 00:00 0
7f6a85299000-7f6a8529a000 r--p 00025000 fc:01 660614 /lib/x86_64-linux-gnu/ld-2.23.so
7f6a8529a000-7f6a8529b000 rw-p 00026000 fc:01 660614 /lib/x86_64-linux-gnu/ld-2.23.so
7f6a8529b000-7f6a8529c000 rw-p 00000000 00:00 0
7ffd4e97f000-7ffd4e9a0000 rw-p 00000000 00:00 0 [stack]
7ffd4e9fb000-7ffd4e9fe000 r--p 00000000 00:00 0 [vvar]
7ffd4e9fe000-7ffd4ea00000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
已放弃 (核心已转储)
若没有core dumped(核心已转储)
字样,这说明CoreDump
功能没有使能,请跳转CoreDump调试指南:CoreDump使能
章节查看,并开启CoreDump
功能。
解析Dump文件
这里使用gdb用于解析CoreDump文件,gdb -c <CoreDumpFile> <app>
命令用于进入gdb控制台。
什么,你找不到<CoreDumpFile>
在哪?请跳转CoreDump调试指南:3、CoreDump输出
章节查看,并根据实际情况找到<CoreDumpFile>
文件。
root@kvm:~/CoreDump# gdb -c TestCoreDump-2582-1712581675 TestCoreDump
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from TestCoreDump...done.
[New LWP 2582]
warning: Unexpected size of section `.reg-xstate/2582' in core file.
Core was generated by `./TestCoreDump'.
Program terminated with signal SIGABRT, Aborted.
warning: Unexpected size of section `.reg-xstate/2582' in core file.
#0 0x00007f6a84cdf438 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54 ../sysdeps/unix/sysv/linux/raise.c: 没有那个文件或目录.
bt
命令用于展开堆栈信息,到这里其实就已经知道了代码出现Dump
的位置了。in dumpCrash () at TestCoreDump.c:6
则代表,Dump
问题位于TestCoreDump
文件的第六行,问题函数是dumpCrash
。
(gdb) bt
#0 0x00007f6a84cdf438 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007f6a84ce103a in __GI_abort () at abort.c:89
#2 0x00007f6a84d217fa in __libc_message (do_abort=do_abort@entry=2, fmt=fmt@entry=0x7f6a84e3af98 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3 0x00007f6a84d2e6e8 in malloc_printerr (ar_ptr=0x0, ptr=<optimized out>, str=0x7f6a84e3afc0 "munmap_chunk(): invalid pointer", action=<optimized out>) at malloc.c:5020
#4 munmap_chunk (p=<optimized out>) at malloc.c:2849
#5 __GI___libc_free (mem=<optimized out>) at malloc.c:2970
#6 0x0000000000400542 in dumpCrash () at TestCoreDump.c:6
#7 0x0000000000400553 in main () at TestCoreDump.c:11
(gdb)
而在源码文件的第六行正好就是我们free一个常量字符串的位置。这当然是不被允许的。
root@kvm:~/CoreDump# nl ./TestCoreDump.c
1 #include "stdio.h"
2 #include "stdlib.h"
3 void dumpCrash()
4 {
5 char *pStr = "test coredump";
6 free(pStr);
7 }
8 int main()
9 {
10 dumpCrash();
11 return 0;
12 }
那么本篇博客就到此结束了,这里只是记录了一些我个人的学习笔记,其中存在大量我自己的理解。文中所述不一定是完全正确的,可能有的地方我自己也理解错了。如果有些错的地方,欢迎大家批评指正。如有问题直接在对应的博客评论区指出即可,不需要私聊我。我们交流的内容留下来也有助于其他人查看,说不一定也有其他人遇到了同样的问题呢😂。