linux调试分析工具

    xiaoxiao2025-07-28  18

    一 strace 系统调用跟踪

    1 strace 参数

    -c 统计每一系统调用的所执行的时间,次数和出错的次数等.  -d 输出strace关于标准错误的调试信息.  -f 跟踪由fork调用所产生的子进程.  -ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.  -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.  -h 输出简要的帮助信息.  -i 输出系统调用的入口指针.  -q 禁止输出关于脱离的消息.  -r 打印出相对时间关于,,每一个系统调用.  -t 在输出中的每一行前加上时间信息.  -tt 在输出中的每一行前加上时间信息,微秒级.  -ttt 微秒级输出,以秒了表示时间.  -T 显示每一调用所耗的时间.  -v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.  -V 输出strace的版本信息.  -x 以十六进制形式输出非标准字符串  -xx 所有字符串以十六进制形式输出.  -a column  设置返回值的输出位置.默认 为40.  -e expr  指定一个表达式,用来控制如何跟踪.格式如下:  [qualifier=][!]value1[,value2]...  qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如:  -eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.  注意有些shell使用!来执行历史记录里的命令,所以要使用\\.  -e trace=set  只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.  -e trace=file  只跟踪有关文件操作的系统调用.  -e trace=process  只跟踪有关进程控制的系统调用.  -e trace=network  跟踪与网络有关的所有系统调用.  -e strace=signal  跟踪所有与系统信号有关的 系统调用  -e trace=ipc  跟踪所有与进程通讯有关的系统调用  -e abbrev=set  设定 strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.  -e raw=set  将指 定的系统调用的参数以十六进制显示.  -e signal=set  指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.  -e read=set  输出从指定文件中读出 的数据.例如:  -e read=3,5  -e write=set  输出写入到指定文件中的数据.  -o filename  将strace的输出写入文件filename  -p pid  跟踪指定的进程pid.  -s strsize  指定输出的字符串的最大长度.默认为32.文件名一直全部输出.  -u username  以username 的UID和GID执行被跟踪的命令

    2 几个使用实例

    (1)寻找被程序读取的配置文件

    [root@v68869 sbin]# strace ./nginx 2>&1 | grep nginx.conf open("/opt/nginx//conf/nginx.conf", O_RDONLY) = 4

    (2)跟踪进程的某个系统调用

    [root@v68869 conf]# strace -e open cat nginx.conf open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 open("nginx.conf", O_RDONLY) = 3

     (3) 跟踪进程

    [root@v68869 conf]# strace -p 23259 strace: Process 23259 attached epoll_wait(8, [{EPOLLIN, {u32=2768318480, u64=139739529293840}}], 512, -1) = 1 accept4(6, {sa_family=AF_INET, sin_port=htons(35326), sin_addr=inet_addr("218.98.33.164")}, [16], SOCK_NONBLOCK) = 3 epoll_ctl(8, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLET, {u32=2768318848, u64=139739529294208}}) = 0 epoll_wait(8, [{EPOLLIN, {u32=2768318848, u64=139739529294208}}], 512, 60000) = 1 recvfrom(3, "CONNECT init.itunes.apple.com:44"..., 1024, 0, NULL, NULL) = 218 writev(3, [{"<html>\r\n<head><title>400 Bad Req"..., 120}, {"<hr><center>nginx/1.0.14</center"..., 53}], 2) = 173 shutdown(3, SHUT_WR) = 0 recvfrom(3, 0x7ffd5fc091b0, 4096, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) epoll_wait(8, [{EPOLLIN|EPOLLHUP, {u32=2768318848, u64=139739529294208}}], 512, 5000) = 1 recvfrom(3, "", 4096, 0, NULL, NULL) = 0 write(5, "218.98.33.164 - - [26/May/2019:2"..., 108) = 108 close(3) = 0 epoll_wait(8, [{EPOLLIN, {u32=2768318480, u64=139739529293840}}], 512, -1) = 1 accept4(6, {sa_family=AF_INET, sin_port=htons(28320), sin_addr=inet_addr("218.98.33.164")}, [16], SOCK_NONBLOCK) = 3 epoll_ctl(8, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLET, {u32=2768318849, u64=139739529294209}}) = 0 epoll_wait(8, [{EPOLLIN, {u32=2768318849, u64=139739529294209}}], 512, 60000) = 1 recvfrom(3, "CONNECT init.itunes.apple.com:44"..., 1024, 0, NULL, NULL) = 218 writev(3, [{"<html>\r\n<head><title>400 Bad Req"..., 120}, {"<hr><center>nginx/1.0.14</center"..., 53}], 2) = 173 shutdown(3, SHUT_WR) = 0 recvfrom(3, 0x7ffd5fc091b0, 4096, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) epoll_wait(8, [{EPOLLIN|EPOLLHUP, {u32=2768318849, u64=139739529294209}}], 512, 5000) = 1 recvfrom(3, "", 4096, 0, NULL, NULL) = 0 write(5, "218.98.33.164 - - [26/May/2019:2"..., 108) = 108

     

    (4)strace的统计概要

    [root@v68869 conf]# strace -c ls fastcgi.conf fastcgi_params.default mime.types nginx.conf.default uwsgi_params fastcgi.conf.default koi-utf mime.types.default scgi_params uwsgi_params.default fastcgi_params koi-win nginx.conf scgi_params.default win-utf % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 25.25 0.001423 51 28 mmap 14.21 0.000801 45 18 mprotect 13.13 0.000740 67 11 open 9.44 0.000532 53 10 read 7.40 0.000417 30 14 close 6.53 0.000368 31 12 fstat 4.56 0.000257 129 2 2 statfs 3.55 0.000200 100 2 getdents 2.41 0.000136 45 3 munmap 2.15 0.000121 61 2 ioctl 1.85 0.000104 35 3 write 1.61 0.000091 30 3 brk 1.17 0.000066 33 2 1 access 1.14 0.000064 32 2 rt_sigaction 0.98 0.000055 55 1 openat 0.98 0.000055 55 1 set_robust_list 0.91 0.000051 51 1 execve 0.83 0.000047 47 1 getrlimit 0.76 0.000043 43 1 set_tid_address 0.71 0.000040 40 1 rt_sigprocmask 0.43 0.000024 24 1 1 stat 0.00 0.000000 0 1 arch_prctl ------ ----------- ----------- --------- --------- ---------------- 100.00 0.005635 120 4 total [root@v68869 conf]# strace -c -p 23259 strace: Process 23259 attached ^Cstrace: Process 23259 detached [root@v68869 conf]# strace -c -p 23259 strace: Process 23259 attached ^Cstrace: Process 23259 detached % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 29.12 0.000316 158 2 writev 19.72 0.000214 43 5 epoll_wait 18.53 0.000201 40 5 2 recvfrom 15.39 0.000167 84 2 shutdown 8.76 0.000095 48 2 epoll_ctl 8.48 0.000092 46 2 accept4 0.00 0.000000 0 1 write 0.00 0.000000 0 1 close ------ ----------- ----------- --------- --------- ---------------- 100.00 0.001085 20 2 total

    二  mtrace 内存泄漏调式工具

    1 安装

    centos系统:  yum install glibc-utils

    2 使用

    #include <stdio.h> int main() { setenv("MALLOC_TRACE", "mtrace.log", "1"); mtrace(); int *p = (int *)malloc(2 * sizeof(int)); return 0; }

    mtrace ()开启内存使用记录,muntrace()用于取消内存使用记录。内存使用情况记录到一个文件,值由环境变量:MALLOC_TRACE决定。

    编译源文件:gcc -g -DDEBUG testmtrace.c

    执行:./a.out 产生mtrace.log

    分析结果:  mtrace ./a.out mtrace.log

    [root@v68869 ~]# mtrace ./a.out mtrace.log - 0x0000000001d04010 Free 3 was never alloc'd 0x7fcd53db596a - 0x0000000001d040f0 Free 4 was never alloc'd 0x7fcd53e771fd - 0x0000000001d04110 Free 5 was never alloc'd 0x7fcd53eeb9dc Memory not freed: ----------------- Address Size Caller 0x0000000001d04590 0x8 at /root/testmtrace.c:19

    3 说明

    mtrace 采用 malloc_hook + return_addr 这两个机制来实现的

    mtrace 会记录所有的分配、释放,包括所有的模块、线程。内存使用记录必将很多,所以官方推荐使用 SIGUSR1或SIGUSR2 来进行开启和关闭内存记录功能。从 mtrace 记录和分析结果可以看到,内存记录日志只记录到 malloc 层面。而实际项目开发时,很多接口都是封装多层才会实际调用到 malloc,对于上面几层的地址,mtrace 没有记录。而上面几层的调用关系才是追踪内存泄漏问题的关键所在。所以在实际开发的项目中,使用 mtrace 不是一个特别好的方法。这里推荐使用 valgrind 工具进行跑流程的方式追踪内存泄漏。如果想要自己记录内存使用情况,可以考虑以下两种方式: 封装一层内存分配、释放的接口函数来记录内存使用情况。项目开发时,统一使用这个接口来进行内存管理。适用于项目尚未开始。使用 malloc_hook 的方式进行记录,项目代码可以不变。适合于项目已经比较庞大了。

     

    三  ltrace 跟踪进程调用库函数

    ltrace 在某些方面和是trace功能类似

    语法:ltrace [option ...] [command [arg ...]]

    Usage: ltrace [option ...] [command [arg ...]] Trace library calls of a given program. -a, --align=COLUMN align return values in a secific column. -c count time and calls, and report a summary on exit. -C, --demangle decode low-level symbol names into user-level names. -d, --debug print debugging info. --dl show calls to symbols in dlopened libraries. -e expr modify which events to trace. -f follow forks. -h, --help display this help and exit. -i print instruction pointer at time of library call. -l, --library=FILE print library calls from this library only. -L do NOT display library calls. -n, --indent=NR indent output by NR spaces for each call level nesting. -o, --output=FILE write the trace output to that file. -p PID attach to the process with the process ID pid. -r print relative timestamps. -s STRLEN specify the maximum string size to print. -S display system calls. -t, -tt, -ttt print absolute timestamps. -T show the time spent inside each call. -u USERNAME run command with the userid, groupid of username. -V, --version output version information and exit. -x NAME treat the global NAME like a library subroutine. [root@bogon bin]# ltrace ./cli (0, 0, 0x1321000, -1, 0x1f25bc2)                                                                 = 0x3c9ba22160 __libc_start_main(0x462ba0, 1, 0x7fff89be1e08, 0x4c6450, 0x4c6440 <unfinished ...> pthread_spin_init(0x7bf600, 0, 0x7fff89be1e18, 8, 0x3c9bf8fba0)                                  = 0 __cxa_atexit(0x4afff0, 0, 0x4c6548, 8, 0x3c9bf8fba0)                                             = 0 __cxa_atexit(0x4a7550, 0, 0x4c6548, 9, 0x3c9bf8fba0)                                             = 0 __cxa_atexit(0x4a7520, 0, 0x4c6548, 10, 0x3c9bf8fba0)                                            = 0 pthread_spin_init(0x7c17e0, 0, 0, 11, 0x3c9bf8fba0)                                              = 0 __cxa_atexit(0x4a2c80, 0, 0x4c6548, 11, 0x3c9bf8fba0)                                            = 0 pthread_spin_init(0x7c18a4, 0, 0, 12, 0x3c9bf8fba0)                                              = 0 __cxa_atexit(0x4a2c70, 0, 0x4c6548, 12, 0x3c9bf8fba0)                                            = 0 strlen("*")                                                                                      = 1 memcpy(0x7c1660, "*", 1)                                                                         = 0x7c1660 __cxa_atexit(0x481290, 0, 0x4c6548, 42, 0x596b7c)                                                = 0 malloc(72)                                                                                       = 0x1bd9c40 pthread_mutex_lock(0x7bf540, 0x3c9bf8ef60, 0x1bd9c40, 81, 0x3c9bf8e188)                          = 0 pthread_mutex_unlock(0x7bf540, 0, 0x1bd9c40, 81, 0x7bf540)                                       = 0 pthread_mutex_lock(0x7bf540, 0, 0x7bf540, 0, 0x7bf540)                                           = 0 pthread_mutex_unlock(0x7bf540, 0, 0x7bf540, 0, 0x7bf540)                                         = 0 pthread_spin_init(0x7c1788, 0, 0x7bf540, 0, 0x7bf540)                                            = 0 pthread_mutex_lock(0x7bf540, 0, 0x7bf540, 0, 0x7bf540)                                           = 0 pthread_cond_broadcast(0x7d1920, 0, 0x7bf540, 0, 0x7bf540)                                       = 0 pthread_mutex_unlock(0x7bf540, 1, 0x7bf540, 0, 0x7bf540)                                         = 0 __cxa_atexit(0x47fab0, 0, 0x4c6548, 0, 0x7bf540)                                                 = 0 pthread_spin_lock(0x7c1788, 13, 0, 15, 0x3c9bf8fba0)                                             = 0 pthread_spin_unlock(0x7c1788, 13, 0, 15, 0x3c9bf8fba0)                                           = 0 pthread_spin_init(0x7c16e8, 0, 0, 15, 0x3c9bf8fba0)                                              = 0 strlen("C")                                                                                      = 1 memcpy(0x7c16f0, "C", 1)                                                                         = 0x7c16f0 malloc(216)                                                                                      = 0x1bd9c90

     

    最新回复(0)