见字如面,我是东北码农。

本文是造轮子-strace的第一篇,我们先介绍strace的功能、使用。下一篇我们来用代码实现一下strace的功能,造个轮子。今天我们先观察、使用轮子。

1、什么是strace

strace是一个Linux的工具,用于记录process的system call的参数、返回值等信息。

strace是我们调试、排障的好帮手,尤其是没有源代码或不方便重新编译的时候。

1.1、小试牛刀

strace使用时非常方便,最简单的方式就是在指令前面加上strace。接下来以telnet为例来看看telnet时调用了哪些system call。

先直接运行一下telnet:

root@xxx:~$ telnet 220.181.38.148 80
Trying 220.181.38.148...
Connected to 220.181.38.148.
Escape character is '^]'.
Connection closed by foreign host.

我们再用strace执行一下telnet:

root@xxx:~$ strace telnet 220.181.38.148 80

...下面省略了一部分...
Trying 220.181.38.148...
socket(AF_INET, SOCK_STREAM, IPPROTO_IP) = 3
setsockopt(3, SOL_IP, IP_TOS, [16], 4) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("220.181.38.148")}, 16) = 0
Connected to 220.181.38.148.
Escape character is '^]'.
setsockopt(3, SOL_SOCKET, SO_OOBINLINE, [1], 4) = 0
recvfrom(3, "", 8191, 0, NULL, NULL) = 0
Connection closed by foreign host.
+++ exited with 1 +++

神奇吧,把telnet调用的system call的参数和返回值打印了出来。上面我只截取了一部分关于网络的system call。

1.2、什么是system call(系统调用)

strace可以跟踪system call,那么什么是system call呢?

为了安全,Linux 中分为用户态和内核态两种运行状态。对于普通进程,平时都是运行在用户态下,仅拥有基本的运行能力。当进行一些敏感操作,比如说要打开文件(open)然后进行写入(write)、分配内存(malloc)时,就会切换到内核态。内核态进行相应的检查,如果通过了,则按照进程的要求执行相应的操作,分配相应的资源。这种机制被称为system call(系统调用),用户态进程发起调用,切换到内核态,内核态完成,返回用户态继续执行,是用户态唯一主动切换到内核态的合法手段(exception 和 interrupt 是被动切换)。

关于系统调用的详细定义可以通过 man syscalls 查看,它列出了目前 Linux Kernel 提供的系统调用 ABI 。我们熟悉的调用比如 open, read ,close 之类的都属于系统调用,但它们都经过了 C 库 (glibc)的封装。实际上,只要符合 ABI 规范,我们可以自己用汇编代码来进行调用。

2、怎么使用strace

学习strace的各种用法,各种参数,推荐两个途径

下面介绍一下我认为比较有用的一些用法。

2.1、两种trace模式

strace也有两种trace模式:

  • strace启动模式:就像上面telnet的例子,正常启动指令前面加strace即可。
  • attach模式:strace -p pid。

strace和gdb很像,二者实现的时候都是依赖ptrace。

2.2、过滤

如果不加过滤,strace会打印所有的system call。即使简单的ls指令,也会调用多达167个system call。所以我们需要根据需求对输出进行一些过滤。

root@xxx:~/code/case/case20_ptrace$ strace ls 2>&1 |wc -l
167
2.2.1、按system call类型过滤

可以按照system call类型过滤,我比较常用的有文件相关、内存相关、网络相关。

-e trace=%file     Trace all system calls which take a file name as an argument.
%memory Trace all memory mapping related system calls.
%network Trace all the network related system calls.
%process Trace all system calls which involve process management.

例如只看文件相关的system call

***@xxx:~$ strace -e trace=%file cat ./out
execve("/usr/bin/cat", ["cat", "./out"], 0x7ffd2b5f1f08 /* 19 vars */) = 0
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "./out", O_RDONLY) = 3
2.2.2、按system call名称过滤

指定system call名称,例如只跟踪connect函数

***@xxx:~$ strace -e trace=connect telnet baidu.com 80
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.30.224.1")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("220.181.38.148")}, 16) = 0
connect(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("220.181.38.251")}, 16) = 0
Trying 220.181.38.148...
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("220.181.38.148")}, 16) = 0
Connected to baidu.com.
Escape character is '^]'.
^Cstrace: Process 371 detached

2.3、system call故障注入

我们可以借助strace,观察process在system call失败时的表现。例如我们可以观察一下,cat打开文件失败时的表现。

在测试时很有用,起到了类似hook的效果。可以测试程序在内存不足、文件访问权限不足、网络不通等异常情况的表现。

root@xxx:~$ strace -e trace=openat -e fault=openat cat ./out
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/haswell/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/haswell/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOSYS (Function not implemented) (INJECTED)
cat: error while loading shared libraries: libc.so.6: cannot open shared object file: Error 38
+++ exited with 127 +++

strace输出:“ (Function not implemented) (INJECTED)”。cat在打开文件失败时输出:“cat: error while loading shared libraries: libc.so.6: cannot open shared object file: Error 38”

2.4、system call信息统计

strace除了可以打印每次system call信息外,还可以使用统计模式。
在性能测试时比较有用。

root@xxx:~$ strace -c -e trace=network telnet baidu.com 80
Trying 220.181.38.148...
Connected to baidu.com.
Escape character is '^]'.
telnet> q
Connection closed.
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
22.93 0.001428 204 7 2 connect
13.12 0.000817 272 3 sendto
13.05 0.000813 135 6 socket
11.24 0.000700 233 3 setsockopt
10.44 0.000650 216 3 recvmsg
9.55 0.000595 198 3 getsockname
7.10 0.000442 221 2 recvfrom
5.15 0.000321 321 1 sendmmsg
3.72 0.000232 232 1 bind
3.71 0.000231 231 1 shutdown
------ ----------- ----------- --------- --------- ----------------
100.00 0.006229 30 2 total
  • time:时间占比
  • seconds:总执行时间
  • usecs/call:平均每次执行时间(微秒)
  • calls:执行次数
  • errors:执行出错次数

3、什么时候使用strace?

3.1、诊断、调试

strace的man手册里是这么介绍自己的

strace  is  a useful diagnostic, instructional, and debugging tool.
System administrators, diagnosticians andtrouble-shooters will find it invaluable
for solving problems with programs for which the source is not readily available since they do not need to be recompiled in order to trace them.

strace是诊断、调试工具。尤其是代码不可用的时候,因为无需重新编译就可以跟踪system call。
例如一个程序调用system call失败退出,但是程序没输出关键日志。通过strace就可以获取调用的参数、返回值、err no。迅速定位问题。

3.2、学习用途

一个程序的实现,无外乎数据+算法+system call。一些“神奇”的程序往往要借助system call实现。例如tcpdump如何实现抓包,gdb如何实现调试。我们都可以使用strace来找灵感。

可以通过strace来了解程序调用了哪些system call,来大致摸清程序实现的骨架。甚至一会我们会利用strace来学习strace是如何实现的。

最后,全网同名,求关注、点赞、转发,谢谢~

造轮子-strace(一)的更多相关文章

  1. 造轮子-strace(二)实现

    这一篇文章会介绍strace如何工作,再稍微深入介绍一下什么是system call.再介绍一下ptrace.wait(strace依赖的system call).最后再一起来造个轮子,动手用代码实现 ...

  2. 避免重复造轮子的UI自动化测试框架开发

    一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...

  3. 【疯狂造轮子-iOS】JSON转Model系列之二

    [疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...

  4. 【疯狂造轮子-iOS】JSON转Model系列之一

    [疯狂造轮子-iOS]JSON转Model系列之一 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 之前一直看别人的源码,虽然对自己提升比较大,但毕竟不是自己写的,很容易遗 ...

  5. h5engine造轮子

    基于学习的造轮子,这是一个最简单,最基础的一个canvas渲染引擎,通过这个引擎架构,可以很快的学习canvas渲染模式! 地址:https://github.com/RichLiu1023/h5en ...

  6. 我为什么还要造轮子?欠踹?Monk.UI表单美化插件诞生记!

    背景 目前市场上有很多表单美化的UI,做的都挺不错,但是他们都有一个共同点,那就是90%以上都是前端工程师开发的,导致我们引入这些UI的时候,很难和程序绑定.所以作为程序员的我,下了一个决定!我要自己 ...

  7. 「iOS造轮子」之UIButton 用Block响应事件

    俗语说 一个不懒的程序员不是好程序员 造轮子,也只是为了以后更好的coding. coding,简易明了的代码更是所有程序员都希望看到的 无论是看自己的代码,还是接手别人的代码 都希望一看都知道这代码 ...

  8. 重复造轮子感悟 – XLinq性能提升心得

    曾经的两座大山 1.EF 刚接触linq那段时间,感觉这家伙好神奇,语法好优美,好厉害.后来经历了EF一些不如意的地方,就想去弥补,既然想弥补,就必须去了解原理.最开始甚至很长一段时间都搞不懂IQue ...

  9. GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。

    1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便 ...

随机推荐

  1. Hbase与Phoenix整合

    目录 一.简介 二.安装 三.Phoenix Shell操作 SCHEMA操作 1.创建schema 2.使用schema 3.删除schema 表操作 1.显示所有表 2.创建表 3.表数据的增删改 ...

  2. 【leetcode】1217. Minimum Cost to Move Chips to The Same Position

    We have n chips, where the position of the ith chip is position[i]. We need to move all the chips to ...

  3. mysql报错max_connections错误

    SELECT @@MAX_CONNECTIONS AS 'Max Connections';set GLOBAL max_connections=10000; show status like '%t ...

  4. linux添加用户、权限

    # useradd –d /usr/sam -m sam 此命令创建了一个用户sam,其中-d和-m选项用来为登录名sam产生一个主目录/usr/sam(/usr为默认的用户主目录所在的父目录). 假 ...

  5. idea2019.2安裝MybatisCodeHelper插件

    1. 下载MybatisCodeHelper插件 下载已破解的插件压缩包,一定注意校验sha1sum!!! 在IDEA中本地安装插件 激活方法(自2.7.3):IDEA顶部菜单:Tools -> ...

  6. gitlab基础命令之代码回滚

    #:gitlab状态 root@ubuntu:~# gitlab-ctl status run: alertmanager: (pid 13305) 215965s; run: log: (pid 1 ...

  7. tomcat 之 httpd session stiky

    # 注释中心主机 [root@nginx ~]# vim /etc/httpd/conf/httpd.conf #DocumentRoot "/var/www/html" #:配置 ...

  8. Redis,Memcache,MongoDb的特点与区别

    Redis Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key - value 缓存产品有以下三个特点: Redis支 ...

  9. 快速上手ANTLR

    回顾前文: ANTLR 简单介绍 ANTLR 相关术语 ANTLR 环境准备 下面通过两个实例来快速上手ANTLR. 使用Listener转换数组 完整源码见:https://github.com/b ...

  10. 【密码学】CBC反转字节攻击

    前言 暑假刷安全牛的课,看视频有点够了,想做点题,选择了实验吧,结果上来就整懵了 web题,牵扯到了CBC反转字节攻击,密码学!? 查阅资料,学习一下 CBC加解密 CBC 模式中会先将明文分组与前一 ...