linux调试技巧分享:strace、ltrace、objdump、valgrind

简介

很多时候我们希望可以看到一个进程调用了哪些API以及其调用顺序,例如我们要参考某个程序的实现,但我们又无法获得该程序的源代码时,使用系统调用跟踪命令不失为一个好办法。另外,在一些无法调试的环境上检查问题时,我们也可以用该命令来查看程序是否按预期执行。strace、ltrace、dtruss都是同一类型的命令,strace是linux系统上的,ltrace是debian类系统上的,而dtruss是mac系统上的。

strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通 过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

命令

strace —— Trace system calls and signals。 跟踪进程的系统调用或信号产生的情况。
ltrace —— A library call tracer。 跟踪进程调用库函数的情况。

strace: (该方法无法发现用户写出的程序或共享库中发生的错误)
strace -o output.txt -T -tt -e trace=all -p 28979
( 跟踪28979进程的所有系统调用(-e trace=all),并统计系统调用的花费时间,
以及开始时间(以时分秒格式显示),最后将记录结果存在output.txt文件里面)



1.使用strace启动进程(假设程序名st1)

    $ strace st1 (//从后往前看strace的输出结果是解决问题的捷径)
    添加-i选项即可显示程序在哪个地址进行了系统调用,该地址可用作设置gdb的断点。
    $ strace -i st1(各行开头[]中的数字就是执行系统调用的代码的地址)
    $ gdb st1
    (gdb) start
    (gdb) b *0x359debf310
    (gdb) c
    (gdb) bt


2.用strace查看运行中的进程(如守护进程)的行为
    ps ux | grep st1(查找st2的进程ID)
    strace -p 17673(假如st进程ID为17673)

3.将strace信息输出到文件
$ strace -o output.log ./st1

4.重定向标准输出
strace的输出为标准错误输出,可以将显示内容输出到标准输出上,通过管道传给grep、less等
$ strace ./st1 2>&1 | grep open 
$ strace ./st1 2>&1 | less
(2>&1 将标准错误重定向到标准输出 2> 标准错误重定向 &1 标准输出)

5.跟踪进程和fork()之后的进程
$ strace -f ./st1

6.显示系统调用的执行时刻
$ strace -t ./st1 (以秒为单位)
$ strace -tt ./st1 (以毫秒为单位)

7.显示特定的系统调用
strace -e open ./st1
strace -e trace=open ./st1
strace -e trace=all ./st1 (默认或-e trace=all表示要显示所有系统调用)

7.ltrace 库调用跟踪(大部分用法基本上与strace一致)
ltrace ./st1

8.objdump 
如果二进制文件带有调试信息,objdump可以将源代码、文件名、行数、汇编代码对应显示,但是优化过的代码可能会对应不准,只能作为参考
objdump -Sl --no-show-raw-insn ./st1

9.valgrind
$ valgrind --tool=memchek --leak-check=yes ./st1
检测内存非法使用(memchek )为默认启用的选项,所以也可以下面这样
valgrind --leak-check=yes ./st1

valgrind并不是万能的,例如对栈上生成的内存区域的非法访问就无法检测到
test.c
#include 
int main(void)
{
    char p[10];
    p[100] = 1;
    return EXIT_SUCCESS;
}

valgrind可用来检测内存泄漏、访问非法内存地址、读取未初始化内存区域、
访问已释放内存区域、内存双重释放、非法栈空间操作。

检测内存泄漏还可以使用top命令,长时间监视内存的使用量。
如果内存泄漏,进程的使用量(VIRT和RES)会时间增长
VIRT和RES的区别是:VIRT包含了被交换(swap)出的空间,而RES不包含。

注意:在VIRT或RES逐渐增加的情况下,有时候不是内存泄漏,可能是库函数
为了提高效率而多分配了内存或者内存不需要时也不释放而是当缓存使用,保持
内存占用。但是这种多余多余分配的内存大小最多只有几MB而已。

 

//文字摘抄自《Debug_Hack》一书,更多应用程序的调试技巧,不妨去网上下载个电子书看看。

如有错误,欢迎留言,哪怕是错别字也好,感谢!

 

你可能感兴趣的:(linux调试技巧)