linux调试分析工具

本文详细介绍了Linux下用于调试的三个工具:strace用于系统调用跟踪,包括参数解析及实例;mtrace是内存泄漏调试工具,讲解了安装和使用方法;ltrace则用于跟踪进程调用的库函数。通过这些工具,开发者能有效地定位和解决Linux程序的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值