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

本文是造轮子-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. 打破砂锅问到底!HTTP和HTTPS详解

    HTTP 引自维基百科HTTP:超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网的数 ...

  2. Android消除Toast延迟显示

    Toast可以用来显示音量改变或者保存更新消息,如果用户一直点击,Toast会排队一个一个的,直到消息队列全部显示完,这样的效果显然是不好的,下面来看解决方法    Toast.makeText(ac ...

  3. 【AWS】【TroubleShooting】EC2实例无法使用SSH远程登陆(EC2 failure for SSH connection)

    1. Login AWS web console and check the EC2 instance.

  4. OpenStack之六: plancement服务(端口8778)

    官网地址:https://docs.openstack.org/placement/stein/install/install-rdo.html #:创建placement库,并授权 MariaDB ...

  5. Dubbo管控平台

    2019年初,官方发布了Dubbo管理控制台0.1版本.结构上采取了前后端分离的方式,前端使用Vue和Vuetify分别作为Javascript框架和UI框架,后端采用Spring Boot框架 一. ...

  6. canal安装与使用

    安装 alpha的版本不是稳定的版本 wget https://github.com/alibaba/canal/releases/download/canal-1.1.4/canal.deploye ...

  7. 使用 OPC Browser 加载 OPC Server 监测点

    1,首先第一步,要连接OPC ,创建好 OPC对象. /// <summary> /// 连接OPC /// </summary> private string OPCIP=1 ...

  8. 密码学之Hash散列

    一.简介 hash(散列.杂凑)函数,是将任意长度的数据映射到有限长度的域上. 直观解释起来,就是对一串数据m进行杂糅,输出另一段固定长度的数据h,作为这段数据的特征(指纹).也就是说,无论数据块m有 ...

  9. Java后端高频知识点学习笔记1---Java基础

    Java后端高频知识点学习笔记1---Java基础 参考地址:牛_客_网 https://www.nowcoder.com/discuss/819297 1.重载和重写的区别 重载:同一类中多个同名方 ...

  10. OpenGL ES2.0 入门经典例子

    原文链接地址:http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial 免责申明(必读!):本博客提供的所有教程的翻译原稿 ...