文章目录

  • 1. Strace命令简介
  • 2. 什么是系统调用
  • 3. Strace的参数
  • 4. Strace的基本用法
  • 5. Strace实战示例
    • 5.1 跟踪特定的系统调用
    • 5.2 跟踪正在执行的程序
    • 5.3 将strace的输出保存到文件中
    • 5.4 打印系统调用摘要
    • 5.5 跟踪自己的程序
  • 6. 总结

1. Strace命令简介

strace命令是一个集诊断调试统计于一体的工具,我们可以用它来监控用户空间进程和内核的交互。比如对应用程序的系统调用信号传递进程状态变更等进行跟踪与分析,以达到解决问题的目的。

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

2. 什么是系统调用

系统调用就是操作系统提供给用户编程时的一些公共子程序,一般为函数或方法。程序可以通过该这些函数或方法向系统内核请求服务

例如,当用户执行read, write, kill, exit等命令时,他们就在进行系统调用。程序会使用各种各样的系统调用来执行各种任务,例如,联网,读写文件,初始化和终止进程等等。

也可以将系统调用看作函数,区别仅在于,系统调用由操作系统提供,系统调用的代码执行时会使CPU的状态由用户态转为核心态,程序运行于内核态。而普通的函数调用由函数库或用户自己提供,由编译链接工具(如gcc)链入用户程序**,库函数的执行不会引起CPU状态的变化,程序运行于用户态**。

3. Strace的参数

在ubuntu下运行 strace -h 命令就可以看到strace命令用法的介绍。

zhongyi@ubuntu:~$ strace -h
usage: strace [-CdffhiqrtttTvVwxxy] [-I n] [-e expr]...[-a column] [-o file] [-s strsize] [-P path]...-p pid... / [-D] [-E var=val]... [-u username] PROG [ARGS]or: strace -c[dfw] [-I n] [-e expr]... [-O overhead] [-S sortby]-p pid... / [-D] [-E var=val]... [-u username] PROG [ARGS]

以下是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执行被跟踪的命令

4. Strace的基本用法

让我们先看一下strace的基本用法。在下面的命令中,使用strace跟踪cp命令,看看它在复制文件时做了那些事情。

zhongyi@ubuntu:~$ strace cp ~/.bashrc bashrc
execve("/bin/cp", ["cp", "/home/zhongyi/.bashrc", "bashrc"], 0x7ffcc7ed9f60 /* 50 vars */) = 0

strace输出中的每一行都包含:系统调用名称括号中传递给系统调用的参数系统调用返回值

输出中看到的第一个系统调用是execve,该调用用于执行带有指定参数数组的程序。

  • "/bin/cp"表示我们要执行的文件的路径。

  • ["cp", "/home/zhongyi/.bashrc", "bashrc"],表示字符串数组,代表要传递给程序的参数,分别对应程序的名称(cp),源路(/home/zhongyi/.bashrc)和目标路径(bashrc)。

  • 0x7ffcc7ed9f60 /* 50 vars */,表示从调用过程继承了46个变量(在execve函数中,环境变量是从外部environ变量获取的)

复制完成后,execve返回0,代表execve系统调用的返回值。发生错误时,返回非0。

5. Strace实战示例

5.1 跟踪特定的系统调用

在使用strace时,有时,我们可能只希望跟踪特定的系统调用。在这种情况下,我们可以使用-e选项后跟一个表达式,该表达式指示应跟踪的系统调用。假设我们运行与上一个示例相同的命令,但是,我们只希望read系统调用显示在输出中。

zhongyi@ubuntu:~$ strace -e read cp ~/.bashrc bashrc
..............省略若干行......
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20b\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\33\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\20\0\0\0\0\0\0"..., 832) = 832
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
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \25\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\16\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000b\0\0\0\0\0\0"..., 832) = 832
read(3, "nodev\tsysfs\nnodev\ttmpfs\nnodev\tbd"..., 1024) = 450
read(3, "", 1024)                       = 0
read(3, "# ~/.bashrc: executed by bash(1)"..., 131072) = 3771
read(3, "", 131072)                     = 0
+++ exited with 0 +++

read系统调用有三个参数:

  • 3,表示文件描述符,与读取的文件相关联。

  • "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20b\0\0\0\0\0\0"...,表示应读取文件的缓冲区。

  • 832,表示应读取的字节数。

读取成功后,该函数将返回从文件读取的字节数。

5.2 跟踪正在执行的程序

strace可以跟踪正在执行的程序。使用方法为 strace -p pid。要找到程序的pid,可以使用pidof命令,例如

zhongyi@ubuntu:~$ pidof gnome-terminal-server
13075

gnome-terminal 为终端进程

得到gnome-terminal-server的pid为13075。使用strace -p 13075命令实时跟踪终端进程执行时的系统调用,打印出的内容如下所示。使用Ctrl+C可以结束跟踪。

zhongyi@ubuntu:~$ strace: Process 13075 attached
..............省略若干行......
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
write(4, "\1\0\0\0\0\0\0\0", 8)         = 8
recvmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\241 \t\f\6\0\200\2\265\1\0\0\316\1\0\0\0\0\0\0\265\2427\242\5\0\0\0\0\0\0\0"..., iov_len=4096}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 4096
recvfrom(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\0\0\0\0"..., 48, 0, NULL, NULL) = 48
recvmsg(3, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="#\204\t\f\32\0\0\0\6\0\2\0\3447q\1\0\0\0\0U\2\0\0\6\0\200\2\0\0\0\0"..., iov_len=4096}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 1768
recvmsg(3, {msg_namelen=0}, 0)          = -1 EAGAIN (Resource temporarily unavailable)
poll([{fd=3, events=POLLIN}, {fd=4, events=POLLIN}, {fd=5, events=POLLIN}], 3, 0) = 1 ([{fd=4, revents=POLLIN}])
strace: Process 13075 detached

5.3 将strace的输出保存到文件中

如果在启动strace时使用-o选项(的缩写--ouput),则可以将其输出重定向到文件,例如:

zhongyi@ubuntu:~$ strace -p 13075 -o strace_output
strace: Process 13075 attached

执行命令后,会自动创建一个strace_output文件,并将strace的输出写进文件中。使用tail strace_output 可以查看文件的最后10行的内容。使用tail -f strace_output会在屏幕上实时更新写进文件的内容。

5.4 打印系统调用摘要

strace还可以显示指定进程的所有系统调用的摘要信息。例如:

strace -c cp ~/.bashrc bashrc

上面的命令将生成如下报告。

zhongyi@ubuntu:~$ strace -c cp ~/.bashrc bashrc
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------18.22    0.001218          53        23           mmap16.11    0.001077          72        15           close15.48    0.001035          65        16           mprotect9.41    0.000629          52        12           openat6.97    0.000466          42        11           read6.76    0.000452          38        12           fstat4.38    0.000293          29        10        10 access3.99    0.000267          89         3           stat2.35    0.000157          79         2         2 statfs2.21    0.000148          74         2           munmap2.06    0.000138          46         3           brk2.03    0.000136         136         1           write1.99    0.000133          67         2           rt_sigaction1.06    0.000071          71         1           arch_prctl1.02    0.000068          68         1           geteuid1.00    0.000067          67         1           prlimit640.99    0.000066          66         1         1 lseek0.99    0.000066          66         1           rt_sigprocmask0.99    0.000066          66         1           set_tid_address0.99    0.000066          66         1           fadvise640.99    0.000066          66         1           set_robust_list0.00    0.000000           0         1           execve
------ ----------- ----------- --------- --------- ----------------
100.00    0.006685                   121        13 total

5.5 跟踪自己的程序

写一个测试程序如下。我们尝试以只读模式打开一个不存在的文件。

#include <stdio.h>
#include <unistd.h>
int main()
{ char str[30]; FILE *fp = fopen("any.txt", "r"); fgets(str, 5, fp); fclose(fp); return 0;
}

编译运行后,正如我们所料,出现了core dumped。

zhongyi@ubuntu:~/workdir/test$ gcc -Wall test.c -o test
zhongyi@ubuntu:~/workdir/test$ ./test
Segmentation fault (core dumped)

尝试使用strace跟踪下test文件,看下到底发生了什么。strace文件的输出如下所示,根据输出内容可以分析定位问题所在。

zhongyi@ubuntu:~/workdir/test$ strace ./test
execve("./test", ["./test"], 0x7ffecbee7d60 /* 51 vars */) = 0
brk(NULL)                               = 0x5621c36a4000
........省略若干行.............
openat(AT_FDCWD, "any.txt", O_RDONLY)   = -1 ENOENT (No such file or directory)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault (core dumped)

在执行test文件时,进行了很多系统调用。然而,我们只需要关注最后四行即可。

从日志信息可以看出,程序是被SIGSEGV终止的,并且产生了段错误 segmentation fault

ENOENT全称为:Error NO EnTry。openat函数返回值为新的文件描述符,出错时,返回-1。而且,在最后也提醒了,No such file or directory。因此,结合源代码,可以判断是操作了不存在的文件。

SIGSEGV是进程进行了一次无效的内存引用(比如访问了一个未经初始化的指针)。si_signo表示信号值。si_code为信号产生的原因,SEGV_MAPERR表示堆栈映射错误。si_addr表示触发fault的内存地址。

6. 总结

关于strace跟踪进程的讲解就到此结束了。strace常用于内核模块编程和系统编程,特别是与文件有关的错误,段错误等。了解系统级的工作方式,有助于我们调试复杂的问题。因此,strace是极力推荐大家掌握的调试工具。

本文参考

https://blog.csdn.net/guotianqing/article/details/79586639

https://www.cnblogs.com/zhangxuechao/p/11709929.html

https://blog.csdn.net/liuzehn/article/details/80657238

https://blog.csdn.net/thisinnocence/article/details/87827963

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_16933601/article/details/117248806
————————————————
版权声明:本文为CSDN博主「嵌入式与Linux那些事」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_16933601/article/details/117248806

【调试技巧】strace神器的使用方法详解与实践相关推荐

  1. phpyun怎么采集_php采集神器cURL使用方法详解

    对于做过数据采集的人来说,cURL一定不会陌生.虽然在PHP中有file_get_contents函数可以获取远程链接的数据,但是它的可控制性太差了,对于各种复杂情况的采集情景,file_get_co ...

  2. Android 抓包神器Fidder使用方法详解:下载,安装,配置,使用教程

    场景: 抓取任何一款手机App的请求连接 问题: 1:有什么好的抓包软件? 2:Fidder怎么使用? 解决方法: 1,常见的抓包软件 (1)Fiddler是位于客户端和服务器端的HTTP代理,也是目 ...

  3. Leetcode怎么调试java代码,IDEA2020.1使用LeetCode插件运行并调试本地样例的方法详解...

    环境: idea2020.1 插件: LeetCode-editor 6.7 一.IDEA安装LeetCode插件 安装完成重启idea 打开插件 URL可以选择国服和世界服.LoginName和Pa ...

  4. php中this的使用技巧,JavaScript中this关键字使用方法详解

    JavaScript中this关键字使用方法详解 在面向对象编程语言中,对于this关键字我们是非常熟悉的.比如C++.C#和Java等都提供了这个关键字,虽然在开始学习的时候觉得比较难,但只要理解了 ...

  5. for根据ID去重_汽车ECU参数标定之配置Overlay RAM实现Qorivva MPC57xx系列MCU参数在线标定和代码重映射原理和方法详解...

    内容提要 引言 1. MPC5744P的Overlay RAM工作原理介绍 2 MPC5744P的Flash Overlay配置详解 2.1 平台Flash标定区域描述字寄存器配置字0--PFLASH ...

  6. android 多闹钟实现代码,Android编程实现闹钟的方法详解

    Android编程实现闹钟的方法详解 发布时间:2020-09-30 10:18:02 来源:脚本之家 阅读:75 作者:Jacob-wj 本文实例讲述了Android编程实现闹钟的方法.分享给大家供 ...

  7. Postman 使用方法详解

    原创 Postman 使用方法详解 2019-07-21 23:28:42 痴乙 阅读数 494053更多 分类专栏: postman 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版 ...

  8. python中fn的用法_Pytorch技巧:DataLoader的collate_fn参数使用详解

    DataLoader完整的参数表如下: class torch.utils.data.DataLoader( dataset, batch_size=1, shuffle=False, sampler ...

  9. python接收邮件内容启动程序_Python实现发送与接收邮件的方法详解

    本文实例讲述了Python实现发送与接收邮件的方法.分享给大家供大家参考,具体如下: 一.发送邮件 这里实现给网易邮箱发送邮件功能: import smtplib import tkinter cla ...

最新文章

  1. Reporting Services 安装的备份和还原操作
  2. Java的从业方向是什么?好找工作吗?
  3. JZTK项目 驾照题库项目servlet层得到的json字符串在浏览器中 汉字部分出现问号?无法正常显示的解决方法
  4. python地理位置聚类_python – 用于聚类地理位置数据的DBSCAN
  5. spring:我是如何解决循环依赖的?
  6. 射击比赛(java)
  7. Android 音视频深入 十四 FFmpeg与OpenSL ES 播放mp3音乐,能暂停(附源码
  8. Resource is out of sync with the file system
  9. arduino调试的流程图_Arduino 的调试以及相关问题
  10. Pandas的时间序列Period,period_range---详解(29)
  11. 谷歌hosts laod
  12. webpack打包时提示:The following entrypoint(s) combined asset size exceeds the recommended limit
  13. 高新技术企业申报认定需要满足哪些条件?
  14. 不同等级的UI设计师工作内容有什么区别?
  15. 【机器学习】阿里云天池竞赛——工业蒸汽量预测(5)
  16. Guitar Pro8苹果mac最新版本下载安装教程
  17. 史上最强!PC时代的20位英雄
  18. win10打印服务器纸规格没有显示,win10系统打印机设置纸张大小的操作方法
  19. python将学号与成绩匹配_python输入学号输出成绩等级_python将百分制成绩转换为等级制输出...
  20. textcnn文本词向量_基于Text-CNN模型的中文文本分类实战

热门文章

  1. 2021年各省市ISO20000体系认证奖励补贴政策
  2. activity串行多实例审批
  3. android bluetooth——蓝牙的开启、搜索、配对与连接
  4. 蹦蹦鸟游戏代码-JavaSE版本
  5. JavaWeb | HTTP 协议请求与响应格式
  6. 零基础学习微信小程序(7):组件
  7. 电脑族科学护眼五常识
  8. 谁你的财神 谁是你的穷神
  9. 人工神经网络英文简称,人工神经网络 英文
  10. HDU1087 噜啦啦卢