当前位置: 首页 > Linux

每天一个Linux命令——strace命令

时间:2023-04-06 19:32:34 Linux

1。命令介绍strace命令是一个集诊断、调试、统计为一体的工具。我们可以使用strace来跟踪程序的系统调用和信号传输,从而对程序进行分析,以达到解决问题或了解程序工作过程的目的。当然,strace不能和gdb等专业的调试工具相提并论,因为它不是专业的调试器。strace最简单的用法就是执行一个指定的命令,执行完指定的命令就退出。命令执行过程中,strace会记录并分析进程的所有系统调用和进程接收到的所有信号值。2.命令格式`strace[OPTIONS]command[ARGS]`3.选项说明`-c统计每次系统调用的时间、次数和错误,并在程序退出时报告摘要-C类似于-c,但是在进程中运行时也会打印常规输出-D将被跟踪进程作为分离的孙进程运行,而不是作为被跟踪对象的父进程运行。这通过将跟踪对象保留为调用进程的直接子进程来减少strace的可见影响-d在stderr上输出strace调试信息-f由fork(2)、vfork(2)和clone(2)调用产生的跟踪Subprocess-ff如果-o提供FILENAME,所有进程的跟踪结果输出到对应的FILENAME.pid,pid为每个进程的进程号-F该选项已废弃,其作用等同于-f-h输出简要帮助信息-i打印系统调用时的指令指针-q禁止attach、detach等信息。当输出被重定向到一个文件并且命令直接运行而不是附加时,这会自动发生-qq如果给出两次,抑制有关进程退出状态的消息-r在每个系统调用条目上打印一个相对时间戳。它记录连续系统调用开始之间的时间差-t在输出中的每一行前面加上一个时间-tt如果给定两次,在输出中的每一行前面加上一个以微秒为单位的时间-ttt如果给定设置三次,打印时间将包括微秒,开始部分将打印自纪元以来的秒数-T显示每个系统调用所花费的时间-v打印所有系统调用。有些调用与环境变量、状态、输入输出等相关,由于使用频繁,默认不输出strace的版本信息。-x以十六进制形式输出非标准字符串-xx所有字符串都以十六进制形式输出-y与文件描述符参数关联的打印路径-aCOLUMN设置返回值的输出位置,默认为40-bSYSCALL如果到达指定的系统调用,从被跟踪的进程中分离。目前,仅支持execve。如果您想跟踪一个多线程进程,因此需要-f,但您不想跟踪其(可能复杂的)子进程,则此选项很有用-eEXPR指定一个控制如何跟踪的表达式。格式如下:[qualifier=][!]value1[,value2]...qualifier只能是trace、abbrev、verbose、raw、signal、read、write其中之一。值是用于限定的符号或数字。默认限定符是trace,感叹号是负号。例如:-eopen等同于-etrace=open,表示只跟踪打开的调用。而-etrace=!open表示跟踪除ope之外的所有其他调用。有两个特殊符号all和none,分别表示跟踪所有系统调用和不跟踪任何系统调用。请注意,某些外壳使用!执行历史命令,所以逃避!带反斜杠的-etrace=SET只跟踪指定的系统调用。例如:-etrace=open,close,rean,write表示只跟踪这四个系统调用,默认为trace=all-etrace=fileonlytraces与文件操作相关的系统调用-etrace=processonlytracesrelatedprocesses受控系统调用-etrace=network跟踪所有与网络相关的系统调用-estrace=signal跟踪所有与系统信号相关的系统调用-etrace=ipc跟踪所有与进程通信相关的系统调用-etrace=desc跟踪所有系统与文件描述符相关的调用-etrace=memory跟踪所有与内存映射相关的系统调用-eabbrev=SET缩写打印大型结构的每个成员的输出。默认为缩写=全部。-v选项的效果是abbrev=none-everbose=S??ET取消对指定系统调用集的结构的引用。默认为verbose=all-eraw=SET以十六进制显示指定系统调用的参数-esignal=SET指定要跟踪的系统信号,默认为signal=all。如signal=!SIGIO(或signal=!io),表示不跟随SIGIO信号-eread=SET输出从指定文件描述符读取的数据。例如:-eread=3,5-ewrite=SET输出数据写入指定文件-oFILENAME将strace的输出写入指定文件-OOVERHEAD设置跟踪系统调用的开销为指定微秒-pPID跟踪指定进程-PPATH只跟踪系统调用的访问路径。多个-P选项可用于指定多个路径-sSTRSIZE指定输出字符串的最大长度,默认为32。注意,文件名不被视为字符串,始终完整打印-SSORTBY对直方图的输出进行排序根据指定的标准由-c选项打印。SORTBY合法值是time,calls,name和nothing,默认是time-uUSERNAME指定用户的UID,GID和supplementarygroup来执行被跟踪的命令-EVAR=VAL为命令设置环境变量-EVAR继承自从环境变量列表中删除变量VAR,然后将其传递给命令`4.常用示例下面我们编写一个非常简单的程序来演示strace的基本用法。该程序的C语言代码如下:`#includeintmain(){inta=0;printf("请输入:n");scanf("%d",&a);printf("%10dn",a);return0;}`用gcc编译,默认生成名为a.out的可执行程序。`gccmain.c`(1)跟踪系统调用。`strace-ostrace.out./a.out`输入4回车生成strace输出文件strace.out,其内容如下:``execve("./a.out",["./a.out"],[/*28vars*/])=0brk(0)=0x1e79000mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0)=0x7ff4e9feb000access("/etc/ld.so.preload",R_OK)=0open("/etc/ld.so.preload",O_RDONLY|O_CLOEXEC)=3fstat(3,{st_mode=S_IFREG|0644,st_size=18,...})=0mmap(NULL,18,PROT_READ|PROT_WRITE,MAP_PRIVATE,3、0)=0x7ff4e9fea000close(3)=0readlink(“/proc/self/exe”,“/root/test/c++/strace/a.out”,4096)=27open(“/lib64/libonion.so",O_RDONLY|O_CLOEXEC)=3read(3,"177ELF21100000000030>01000`20000000"...,832)=832fstat(3,{st_mode=S_IFREG|0755,st_size=42880,...})=0mmap(NULL,1072448,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_DENYWRITE,3,0)=0x7ff4e9ee4000mprotect(0x7ff4e9ee7000,1048576,PROT_NONE)=0mmap(0x7ff4e9fe7000,4096|te|map_fixed|map_denywrite,3,0x3000)=0x7ff4e9fe7000mmap(0x7ff4e9fe8000,7488,7488,prot_read|prot_write,map_private|map_fixed|map_fixed|map_anonymous,-1,0)/ld.so.cache",O_RDONLY|O_CLOEXEC)=3fstat(3,{st_mode=S_IFREG|0644,st_size=74350,...})=0mmap(NULL,74350,PROT_READ,MAP_PRIVATE,3,0)=0x7ff4e9ed1000close(3)=0open("/lib64/libc.so.6",O_RDONLY|O_CLOEXEC)=3read(3,"177ELF21130000000030>010002035200000"...,832)=832fstat(3,{st_mode=S_IFREG|0755,st_size=2122016,...})=0mmap(null,3944896,prot_read|prot_exec,map_private|map_denywrite,3,0)=0x7ff4e9a07000mprotect(0x7ff4e9bc1000,2093056,prot_none)|MAP_DENYWRITE,3,0x1b9000)=0x7ff4e9dc0000mmap(0x7ff4e9dc6000,16832,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,-1,0)=0x7ff4e9dc6000close(3)=0mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0)=0x7ff4e9fea000open("/lib64/libdl.so.2",O_RDONLY|O_CLOEXEC)=3read(3,"177ELF21100000000030>01000`16000000"...,832)=832fstat(3,{st_mode=S_IFREG|0755,st_size=19344,...})=0mmap(NULL,2109744,PROT_READ|PROT_EXEC,map_private|map_denywrite,3,0)=0x7ff4e9803000mprotect(0x7ff4e9805000,2097152,prot_none)=0mmap(0x7ff4e9a05000,8192,8192prot_read|prot_write,map_private|map_anonymous,-1,0)=0x7ff4e9ecf000Arch_prctl(Arch_set_set_fs,0x7ff4e9ecf740)=0mprotect(0x7ff4e9dc0000,yrect_16384,prot_read)=0MREAT_000MPROTECT(0MMMETT)=0MPROTECT(0MMPROT)0x7ff4e9fec000,4096,PROT_READ)=0munmap(0x7ff4e9ed1000,74350)=0fstat(1,{st_mode=S_IFCHR|0620,st_rdev=makedev(136,1),...})=0mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0)=0x7ff4e9ee3000write(1,"请输入:n",14)=14fstat(0,{st_mode=S_IFCHR|0620,st_rdev=makedev(136,1),...})=0mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0)=0x7ff4e9ee2000read(0,"4n",1024)=2write(1,"4n",11)=11exit_group(0)=?+++以0+++``退出从跟踪结果可以看出,系统首先调用execve启动一个新的进程,然后初始化环境,最后停在read(0,"4n",1024)=2处,也就是说scanf函数已经执行完毕executedandwaitfor我们输入数字4后,调用write函数将格式化后的值4输出到屏幕,最后调用exit_group退出进程,完成整个程序的执行。(2)轨道信号传输。我们仍然使用上面的a.out程序来观察进程接收到的信号,即跟踪与进程和信号相关的系统调用。`#Opentracestrace-etrace=signal-ostrace.out./a.out#Findprocess./a.outprocessIDps-ef|grepa.out|grep-v"grep|strace"root1078710784022:46pts/100:00:00./a.out#根据上一步找到的进程ID,通过发送信号SIGKILLkill-910787`kill命令再次检查strace输出文件strace.out的内容。`---SIGWINCH{si_signo=SIGWINCH,si_code=SI_KERNEL}------SIGWINCH{si_signo=SIGWINCH,si_code=SI_KERNEL}---+++killedbySIGKILL+++`当进程被杀死并退出时,strace会输出killedbySIGX(SIGX代表发送给进程的信号)等,那么进程自己退出会输出什么呢?这里有一个名为test_exit的程序,它的代码如下:`#include#includeintmain(intargc,char**argv){exit(1);}`让我们跟踪到查看strace退出时可以看到哪些痕迹。`strace-tt-etrace=process-f./test_exit`-etrace=process表示只跟踪进程管理相关的系统调用。输出:`23:07:24.672849execve("./test_exit",["./test_exit"],[/*35vars*/])=023:07:24.674665arch_prctl(ARCH_SET_FS,0x7f1c0eca7740)=023:07:24.675108exit_group(1)=?23:07:24.675259+++exitedwith1+++`可以看出,当进程自行退出时(调用exit函数,或者从main函数返回),最后调用是exit_group系统调用,strace会输出exitedwithX(X是退出码)。可能有人会疑惑,代码明明调用了exit,怎么会显示成exit_group呢?这是因为这里的exit函数不是系统调用,而是glibc库提供的函数。exit函数的调用最终会转化为exit_group系统调用。它退出当前进程的所有线程。事实上,有一个名为_exit()(注意exit前面的下划线)的系统调用最终会在线程退出时被调用。(3)系统调用统计。strace不仅可以跟踪系统调用,还可以通过参数-c为你统计分析进程的所有系统调用。我们来看看strace对系统调用的统计。`strace-c./a.outpleaseinput:44%timesecondsusecs/callcallserrorssyscall------------------------------------------------------------100.000.000038315mmap0.000.00000004读取0.000.00000002写入0.000.00000005open0.000.00000005close0.000.00000007fstat0.000.00000007mprotect0.000.00000002munmap0.000.00000001brk0.000.00000001access0.000.00000001execve0.000.00000001readlink0.000.00000001arch_prctl-------------------------------------------------------------100.000.00003852total`这个很清楚的告诉你调用了哪些系统函数,调用了多少次,消耗了多少时间等等,这对于我们分析一个program非常有用(4)跟踪一个现有的进程。strace不仅可以自己初始化一个进程进行trace,还可以使用-p选项来trace已有的进程。具体用法如下:strace-pPID