01 总览编译阶段
符号:函数、变量 参数:
功能: 获取二进制文件里面的字符串常量 用途: 比较重要的是检查KEY泄露 eg:strings <your_proc> | grep '^.\{16\}$' 查找<your_proc>中是否存在一行有16个字符的行,并显示出来。 选项:
GLIBC_2.0 GLIBC_2.1 GLIBC_2.1.1 …… 这样就能看到glibc支持的版本。 strip(去除二进制文件里面包含的符号)用途: 可执行程序减肥(通常只在已经调试和测试过的生成模块上,因为不能调试了) 反编译、反跟踪 readelf(显示目标文件详细信息)nm 程序可用于列举符号及其类型和值,但是,要更仔细地研究目标文件中这些命名段的内容,需要使用功能更强大的工具。其中两种功能强大的工具是objdump和readelf。 readelf工具使用来显示一个或多个ELF格式文件信息的GNU工具。使用不同的参数可以查看ELF文件不同的的信息。 readelf <option> <elffile>
objdump(尽可能反汇编出源代码)objdump –S <exe> 尽可能反汇编出源代码,尤其当编译的时候指定了-g参数时,效果比较明显。 addr2line(根据地址查找代码行)当某个进程崩溃时,日志文件(/var/log/messages)中就会给出附加的信息,包括程序终止原因、故障地址,以及包含程序状态字(PSW)、通用寄存器和访问寄存器的简要寄存器转储。 eg:Mar 31 11:34:28 l02 kernel: failing address: 0 如果可执行文件包括调试符号(带-g编译的),使用addr2line,可以确定哪一行代码导致了问题。 eg:addr2line –e exe addr 其实gdb也有这个功能,不过addr2line的好处是,很多时候,bug很难重现,我们手上只有一份crash log。这样就可以利用addr2line找到对应的代码行,很方便。 注意:
参数:
调试程序的常见步骤: 1、确定运行时间主要花在用户态还是内核态(比较土的一个方法:程序暂时屏蔽daemon()调用,hardcode收到n个请求后exit(0),time一下程序……)。 2、如果是用户态,则使用gprof进行性能分析。 3、如果是内核态,则使用strace进行性能分析,另外可以使用其他工具(比如ltrace等)辅助。 ldd(显示程序需要使用的动态库和实际使用的动态库)# ldd /bin/lslinux-gate.so.1 => (0xbfffe000) librt.so.1 => /lib/librt.so.1 (0xb7f0a000) libacl.so.1 => /lib/libacl.so.1 (0xb7f04000) libc.so.6 => /lib/libc.so.6 (0xb7dc3000) libpthread.so.0 => /lib/libpthread.so.0 (0xb7dab000) /lib/ld-linux.so.2 (0xb7f1d000) libattr.so.1 => /lib/libattr.so.1 (0xb7da6000) 第一栏:需要用什么库;第二栏:实际用哪个库文件;第三栏:库文件装载地址。 如果缺少动态库,就会没有第二栏。 strace(跟踪当前系统调用)结果默认输出到2。
如:strace -f -o ~/<result_file> <your_proc>
使用 strace –e open ./prg 来看程序使用了哪些配置文件或日志文件,很方便。
例如:-e trace=open,close,rean,write 表示只跟踪这四个系统调用.
参数和strace很接近 time(查看程序执行时间、用户态时间、内核态时间)# time ps aux | grep 'hi'1020 21804 0.0 0.0 1888 664 pts/6 S+ 17:46 0:00 grep hi real 0m0.009s user 0m0.000s sys 0m0.004s 注意: time只跟踪父进程,所以不能fork gprof(显示用户态各函数执行时间)gprof原理:
使用步骤: 1、使用 -pg 编译和链接应用程序 gcc -pg -o exec exec.c 如果需要库函数调用情况: gcc -lc_p -gp -o exec exec.c 2、执行应用程序使之生成供gprof 分析的数据gmon.out 3、使用gprof 程序分析应用程序生成的数据 gprof exec gmon.out > profile.txt 注意: 程序必须通过正常途径退出(exit()、main返回),kill无效。对后台常驻程序的调试——我的比较土方法是,屏蔽daemon()调用,程序hardcode收到n个请求后exit(0)。 有时不太准。 只管了用户态时间消耗,没有管内核态消耗。 gdb core exec (gdb查看core文件) 准备生成core: 启动程序前,ulimit -c unlimited,设置core文件不限制大小。(相反,ulimit -c 0,可以阻止生成core文件) 默认在可执行程序的路径,生成的是名字为core的文件,新的core会覆盖旧的。 设置core文件名字: /proc/sys/kernel/core_uses_pid 可以控制产生的core文件的文件名中是否添加pid作为扩展,1为扩展,否则为0。 proc/sys/kernel/core_pattern 可以设置格式化的core文件保存位置或文件名,比如原来文件内容是core,可以修改为: echo "/data/core/core-%e-%p-%t" > core_pattern 以下是参数列表:
使用gdb查看core: gdb <program> <core文件> opprofile (查看CPU耗在哪)常用命令 使用oprofile进行cpu使用情况检测,需要经过初始化、启动检测、导出检测数据、查看检测结果等步骤,以下为常用的oprofile命令。 初始化
检测控制
查看检测结果
CPU: Core 2, speed 2128.07 MHz (estimated) Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (Unhalted core cycles) count 100000CPU_CLK_UNHAL T.........| samples | %| ------------------------ 31645719 87.6453 no-vmlinux 4361113 10.3592 libend.so 7683 0.1367 libpython2.4.so.1.0 7046 0.1253 op_test valgrind(检查内存错误) 使用步骤: 1、官网下载并安装valgrind。 2、-g编译的程序都可以使用。 官网的示例代码test.c #include <stdlib.h>void f(void) { int* x = malloc(10 * sizeof(int)); x[10] = 0; // problem 1: heap block overrun } // problem 2: memory leak -- x not freed int main(void) { f(); return 0; } 编译程序gcc -Wall -g -o test test.c 3、valgrind启动程序,屏幕输出结果。 valgrind --tool=memcheck --leak-check=full ./test 注意: valgrind只能查找堆内存的访问错误,对栈上的对象和静态对象没办法。 valgrind会影响进程性能,据说可能慢20倍,所以在性能要求高的情况下,只能使用mtrace这种轻量级的工具了(但是mtrace只能识别简单的内存错误)。 如果程序生成的core的堆栈是错乱的,那么基本上是stackoverflow了。这种情况,可以通过在编译的时候,加上 –fstack-protector-all 和 -D_FORTIFY_SOURCE=2 来检测。Stack-protector-all 会在每个函数里加上堆栈保护的代码,并在堆栈上留上指纹。(记录下,没用过) 因为valgrind 查不了栈和静态对象的内存访问越界,这类问题,可以通过使用gcc的-fmudflap –lmudflap 来检测。(记录下,没用过) 全局变量的类型不一致的问题,现在还找到比较好的方法,这从另一个方面说明全局对象不是个好的设计,这给调试带来了麻烦。 mtrace(检查内存错误)mtrace是glibc內提供的工具,原理很简单,就是把你程序中malloc()和free()的位置全部下來,最后两辆配对,沒有配对到的就是memory leak。 使用的步骤如下: 1、代码中添加mtrace() #include <stdio.h>#include <stdlib.h> int main(void) { int *p; int i; #ifdef DEBUG setenv("MALLOC_TRACE", "./memleak.log", 1); mtrace(); #endif p=(int *)malloc(1000); return 0; } 这段代码malloc了一个空间,却沒有free掉。我们添加9-12行的mtrace调用。 2、编译gcc -g -DDEBUG -o test1 test1.c 3、执行./test1,在目录里会发现./memleak.log。 4、使用mtrace <your_proc> memleak.log 查看信息。 # mtrace test1 memleak.log- 0x0804a008 Free 3 was never alloc'd 0xb7e31cbe - 0x0804a100 Free 4 was never alloc'd 0xb7ec3e3f - 0x0804a120 Free 5 was never alloc'd 0xb7ec3e47 Memory not freed: ----------------- Address Size Caller 0x0804a4a8 0x3e8 at /home/illidanliu/test1.c:14 可以看到test1.c没有对应的free()。 04 其他proc文件系统内核的窗口。 proc文件系统是一个伪文件系统,它存在内存当中,而不占用外存空间。 用户和应用程序可以通过proc得到系统的信息,并可以改变内核的某些参数。 proc/目录结构(部分):
proc/<pid>/目录结构(部分):
/var/log/下的日志文件:
|
| 顶一下 |
微信公众号
手机版