Linux 命令(137)—— strace 命令
1.命令简介
strace 命令是一个集诊断、调试、统计于一体的工具,我们可以使用 strace 跟踪程序的系统调用和信号传递来对程序进行分析,以达到解决问题或者是了解程序工作过程的目的。当然 strace 与专业的调试工具比如说 gdb 之类的是没法相比的,因为它不是一个专业的调试器。
strace 的最简单的用法就是执行一个指定的命令,在指定的命令结束之后它也就退出了。在命令执行的过程中,strace 会记录和解析进程的所有系统调用以及这个进程所接收到的所有信号值。
2.命令格式
strace [OPTIONS] command [ARGS]
3.选项说明
-c统计每个系统调用的时间、次数和错误,并在程序退出时报告摘要
-C类似于 -c,但在进程运行时也打印常规输出
-D将跟踪进程作为分离的孙进程运行,而不是作为跟踪对象的父进程运行。这通过保持跟踪对象是调用进程的直接子进程来减少 strace 的可见效果
-d输出 strace 关于标准错误的调试信息
-f跟踪由 fork(2), vfork(2) and clone(2) 调用所产生的子进程
-ff如果提供 -o FILENAME,则所有进程的跟踪结果输出到相应的 FILENAME.pid 中,pid 是各进程的进程号
-F该选项已废弃,作用等同于 -f
-h输出简要的帮助信息
-i在系统调用时打印指令指针
-q禁止附加、分离等信息。当输出被重定向到文件并直接运行命令而不是附加命令时,这将自动发生
-qq如果给定两次,则禁止关于进程退出状态的消息
-r在每次系统调用进入时打印相对时间戳。它记录连续系统调用开始之间的时间差
-t在输出中的每一行前加上时间信息
-tt如果给定两次,在输出中的每一行前加上微秒级的时间信息
-ttt如果给定三次,则打印的时间将包括微秒,并且开始部分将打印自纪元以来的秒数
-T显示每一系统调用所耗的时间
-v输出所有的系统调用。一些调用关于环境变量,状态,输入输出等调用,由于使用频繁默认不输出
-V输出 strace 的版本信息.
-x以十六进制形式输出非标准字符串
-xx所有字符串以十六进制形式输出
-y与文件描述符参数关联的打印路径
-a COLUMN设置返回值的输出位置,默认为40
-b SYSCALL如果达到指定的系统调用,与跟踪进程分离。目前,只支持 execve。如果希望跟踪多线程进程,因此需要 -f,但不希望跟踪其(可能非常复杂的)子进程,则此选项非常有用
-e EXPR指定一个表达式,用来控制如何跟踪。格式如下: [qualifier=][!]value1[,value2]... qualifier 只能是 trace, abbrev, verbose, raw, signal, read, write 其中之一。value 是用来限定的符号或数字。默认的 qualifier 是 trace,感叹号是否定符号。例如:-e open 等价于 -e trace=open,表示只跟踪 open 调用。而 -etrace=!open 表示跟踪除了 ope 以外的所有其他调用。有两个特殊的符号 all 和 none,分别表示跟踪所有和不跟踪任何系统调用。注意有些 Shell 使用 ! 来执行历史记录里的命令,所以要使用反斜杠对 ! 进行转义
-e trace=SET只跟踪指定的系统调用。例如: -e trace=open,close,rean,write 表示只跟踪这四个系统调用,默认的为 trace=all
-e trace=file只跟踪有关文件操作的系统调用
-e trace=process 只跟踪有关进程控制的系统调用
-e trace=network 跟踪与网络有关的所有系统调用
-e strace=signal跟踪所有与系统信号有关的系统调用
-e trace=ipc 跟踪所有与进程通讯有关的系统调用
-e trace=desc跟踪所有与文件描述符相关的系统调用
-e trace=memory跟踪所有与内存映射相关的系统调用
-e abbrev=SET缩写打印大型结构的每个成员的输出。默认值是 abbrev=all。-v 选项的效果是 abbrev=none
-e verbose=SET为指定的系统调用集取消引用结构。默认是 verbose=all
-e raw=SET将指定的系统调用的参数以十六进制显示
-e signal=SET指定跟踪的系统信号,默认为 signal=all。如 signal=!SIGIO(或 signal=!io),表示不跟踪 SIGIO 信号
-e read=SET输出从指定文件描述符中读出的数据。例如:-e read=3,5
-e write=SET输出写入到指定文件中的数据
-o FILENAME将 strace 的输出写入指定文件
-O OVERHEAD将跟踪系统调用的开销设置为指定的微秒
-p PID跟踪指定的进程
-P PATH只跟踪系统调用的访问路径。多个 -P 选项可用于指定多个路径
-s STRSIZE指定输出的字符串的最大长度,默认为 32。注意,文件名不被认为是字符串,总是全部打印
-S SORTBY根据指定的条件对 -c 选项打印的直方图的输出进行排序。SORTBY 合法值是 time、calls、name 和 nothing,默认值是 time
-u USERNAME以指定用户的 UID、GID 和补充组执行被跟踪的命令
-E VAR=VAL为命令设置环境变量-E VAR从继承的环境变量列表中删除变量 VAR,然后将其传递给命令
4.常用示例
现在我们做一个很简单的程序来演示 strace 的基本用法。这个程序的 C 语言代码如下:
#include<stdio.h>
int main()
{int a = 0;printf("please input:\n");scanf("%d", &a);printf("%10d\n", a); return 0;
}
通过 gcc 编译,默认生成名为 a.out 的可执行程序。
gcc main.c
(1)追踪系统调用。
strace -o strace.out ./a.out
输入 4 然后回车生成 strace 的输出文件 strace.out,其内容如下:
execve("./a.out", ["./a.out"], [/* 28 vars */]) = 0
brk(0) = 0x1e79000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff4e9feb000
access("/etc/ld.so.preload", R_OK) = 0
open("/etc/ld.so.preload", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0
mmap(NULL, 18, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0x7ff4e9fea000
close(3) = 0
readlink("/proc/self/exe", "/root/test/c++/strace/a.out", 4096) = 27
open("/lib64/libonion.so", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\20\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=42880, ...}) = 0
mmap(NULL, 1072448, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff4e9ee4000
mprotect(0x7ff4e9ee7000, 1048576, PROT_NONE) = 0
mmap(0x7ff4e9fe7000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7ff4e9fe7000
mmap(0x7ff4e9fe8000, 7488, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ff4e9fe8000
close(3) = 0
munmap(0x7ff4e9fea000, 18) = 0
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=74350, ...}) = 0
mmap(NULL, 74350, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff4e9ed1000
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2122016, ...}) = 0
mmap(NULL, 3944896, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff4e9a07000
mprotect(0x7ff4e9bc1000, 2093056, PROT_NONE) = 0
mmap(0x7ff4e9dc0000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b9000) = 0x7ff4e9dc0000
mmap(0x7ff4e9dc6000, 16832, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7ff4e9dc6000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff4e9fea000
open("/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\16\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=19344, ...}) = 0
mmap(NULL, 2109744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7ff4e9803000
mprotect(0x7ff4e9805000, 2097152, PROT_NONE) = 0
mmap(0x7ff4e9a05000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7ff4e9a05000
close(3) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff4e9ecf000
arch_prctl(ARCH_SET_FS, 0x7ff4e9ecf740) = 0
mprotect(0x7ff4e9dc0000, 16384, PROT_READ) = 0
mprotect(0x7ff4e9a05000, 4096, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ) = 0
mprotect(0x7ff4e9fec000, 4096, PROT_READ) = 0
munmap(0x7ff4e9ed1000, 74350) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff4e9ee3000
write(1, "please input:\n", 14) = 14
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff4e9ee2000
read(0, "4\n", 1024) = 2
write(1, " 4\n", 11) = 11
exit_group(0) = ?
+++ exited with 0 +++
从跟踪的结果可以看到,系统首先调用 execve 开始一个新的进程,接着进行环境的初始化操作,最后停顿在read(0, "4\n", 1024) = 2
,这也就是执行到了 scanf 函数,等待我们输入数字。在输入完 4 之后,再调用 write 函数将格式化后的数值4
输出到屏幕,最后调用 exit_group 退出进程,完成整个程序的执行过程。
(2)跟踪信号传递。我们还是使用上面的 a.out 程序,来观察进程接收信号的情况,即跟踪进程和信号相关的系统调用。
#开启跟踪
strace -e trace=signal -o strace.out ./a.out#查找进程 ./a.out 进程 ID
ps -ef | grep a.out | grep -v "grep\|strace"
root 10787 10784 0 22:46 pts/1 00:00:00 ./a.out#根据上一步查到的进程 ID 通过 kill 命令发送信号 SIGKILL
kill -9 10787
再次查看 strace 的输出文件 strace.out 的内容。
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
--- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
+++ killed by SIGKILL +++
进程被杀退出时,strace 会输出 killed by SIGX(SIGX 代表发送给进程的信号)等,那么进程自己退出时会输出什么呢?
这里有个叫做 test_exit 的程序,其代码如下:
#include <stdio.h>
#include <stdlib.h>int main(int argc, char **argv)
{exit(1);
}
我们 strace 看下它退出时 strace 上能看到什么痕迹。
strace -tt -e trace=process -f ./test_exit
-e trace=process 表示只跟踪和进程管理相关的系统调用。
输出:
23:07:24.672849 execve("./test_exit", ["./test_exit"], [/* 35 vars */]) = 0
23:07:24.674665 arch_prctl(ARCH_SET_FS, 0x7f1c0eca7740) = 0
23:07:24.675108 exit_group(1) = ?
23:07:24.675259 +++ exited with 1 +++
可以看出,进程自己退出时(调用 exit 函数,或者从 main 函数返回), 最终调用的是 exit_group系统调用, 并且 strace 会输出 exited with X(X为退出码)。
可能有人会疑惑,代码里面明明调用的是 exit, 怎么显示为 exit_group?
这是因为这里的 exit 函数不是系统调用,而是 glibc 库提供的一个函数,exit 函数的调用最终会转化为 exit_group 系统调用,它会退出当前进程的所有线程。实际上,有一个叫做 _exit() 的系统调用(注意 exit 前面的下划线)线程退出时最终会调用它。
(3)系统调用统计。strace 不光能追踪系统调用,通过使用参数 -c,它还能将进程所有的系统调用做一个统计分析给你,下面来看看 strace 对系统调用的统计。
strace -c ./a.out
please input:
44
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00 0.000038 3 15 mmap0.00 0.000000 0 4 read0.00 0.000000 0 2 write0.00 0.000000 0 5 open0.00 0.000000 0 5 close0.00 0.000000 0 7 fstat0.00 0.000000 0 7 mprotect0.00 0.000000 0 2 munmap0.00 0.000000 0 1 brk0.00 0.000000 0 1 access0.00 0.000000 0 1 execve0.00 0.000000 0 1 readlink0.00 0.000000 0 1 arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00 0.000038 52 total
这里很清楚的告诉你调用了那些系统函数,调用次数多少,消耗了多少时间等等这些信息,这个对我们分析一个程序来说是非常有用的。
(4)trace 一个现有的进程。strace 不光能自己初始化一个进程进行 trace,还能使用 -p 选项追踪现有的进程。具体用法如下:
strace -p PID
参考文献
[1] strace(1) manual
[2] Linux 命令大全.strace
[3] 马昌伟.strace命令详解
Linux 命令(137)—— strace 命令相关推荐
- linux服务器跟踪命令,Linux下使用strace命令来跟踪.htaccess的使用
一般情况下,不应该使用.htaccess文件,除非你对Linux主服务器配置文件没有存取权限. 实际情况下,很多时候我们在不知情的条件下开启了.htaccess文件的支持,降低了apache的性能,下 ...
- linux基础 linux命令跟踪 strace命令
原文: (909条消息) Linux之strace命令_风华浪浪的博客-CSDN博客_linux strace trace :监控程序的执行状况 在linux 空间下,运行一个程序时,操作系统会将应用 ...
- Linux进程照妖镜strace命令
strace是个功能强大的Linux调试分析诊断工具,可用于跟踪程序执行时进程系统调用(system call)和所接收的信号,尤其是针对源码不可读或源码无法再编译的程序.在Linux系统中,用户进程 ...
- Linux应用调试-strace命令
1.strace简介 strace常用来跟踪进程执行时的系统调用和所接收的信号.通过strace可以知道应用程序打开了哪些文件,以及读写了什么内容,包括消耗的时间以及返回值等 2.安装strace命令 ...
- Linux命令之strace命令
一.命令简介 strace是一个有用的诊断.指导和调试工具.系统管理员.诊断专家和故障解决人员将发现,对于解决源代码不易获得的程序的问题,这是非常宝贵的,因为它们不需要重新编译以跟踪它们.学生.黑 ...
- linux的strace命令(详解)
linux的strace命令(详解) 本文详细讲述linux下的strace命令的用法. strace 命令是一种强大的工具,它能够显示所有由用户空间程序发出的系统调用. strace 显示这些调用的 ...
- 性能分析工作strace命令用法详解及使用例子
1 功能说明 strace 命令是一种强大的工具, 能够显示任何由用户空间程式发出的系统调用. strace 显示这些调用的参数并返回符号形式的值. strace 从内核接收信息, 而且无需以任何特别 ...
- linux的strace命令
linux的strace命令 strace 命令是一种强大的工具,它能够显示所有由用户空间程序发出的系统调用. strace 显示这些调用的参数并返回符号形式的值.strace 从内核接收信息,而且不 ...
- linux跟踪线程的方法:LWP和strace命令
摘要:在使用多线程程序时,有时会遇到程序功能异常的情况,而这种异常情况并不是每次都发生,很难模拟出来.这时就需要运用在程序运行时跟踪线程的手段,而linux系统的LWP和strace命令正是这种技术手 ...
最新文章
- 深入 Python 解释器源码,我终于搞明白了字符串驻留的原理!
- java+构建+工具+Ant+Maven+Gradle
- mysql的付费功能_MYSQL对游戏用户付费行为分析
- Netty的Socket编程详解-搭建服务端与客户端并进行数据传输
- 【深度学习】实战深度学习检测疟疾
- 【物联网工厂大揭秘】电路板、数传模块 是怎么生产制造出来的?
- CodeForce 180 C ——Letter
- insert函数的修改,
- 云+X案例展 | 民生类:肯耐珂萨入围腾讯SaaS加速器首期成员名单
- Git简单命令 学习资源贴
- linux中波浪线是根目录吗,linux 波浪线 ~ 使用方法
- su室外渲染参数设置_紫天资源星球下载:多层公寓楼室外Lumion预渲染场景
- 机器学习2-Logistic回归
- php 查询access数据库操作,php操作access数据库的方法详解
- 人脸对齐:Procrustes analysis 普氏分析
- msdp rpf 规则1
- 极米H5搭载全新CCB流明,树电影色彩亮度新标杆
- 双阶乘java,超级公式计算器-官方版合集下载-多特
- 2019各大互联网公司校园招聘流程
- PSO粒子群算法调节PID控制器参数
热门文章
- Mongodb 与 MySQL对比
- Dynamic Entity Representation with Max-pooling Improves Machine
- Snowflake Snow Snowflakes--POJ 3349
- 在FreeBSD上彻底禁用sendmail
- Spring 事务传播原理及数据库事务操作原理
- SpringBoot之Listener注册到Spring容器中的多种方法
- PAT 1084. 外观数列 (20) - 乙级
- js阻止鼠标右击_使用JS 禁止键盘快捷方式和禁止鼠标右键操作弹窗提示
- 字符数组查找-----拉手笔试
- MongoDB最大连接数的查看与修改