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

本文是造轮子-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. Oracle——生成Awr报告

    Oracle--生成Awr报告 AWR的概念 Oracle数据库是一个使用量很多的数据库,关于Oracle数据库的性能.Oracle10g以后,Oracle提供了一个性能检测的工具:AWR(Autom ...

  2. collection映射

    讲了manyToOne和oneToMany,下面来看看get方法.在之前已经说过,如果是映射单对象,直接使用association来映射.而如果关系 是一个集合,则需要使用collection来描述. ...

  3. Linux学习 - 系统定时任务

    1 crond服务管理与访问控制 只有打开crond服务打开才能进行系统定时任务 service crond restart chkconfig crond on 2 定时任务编辑 crontab [ ...

  4. SpringMVC注解详情

    @Component.@Repository @Service.@Controller 看字面含义,很容易却别出其中三个: @Controller 控制层,就是我们的action层 @Service ...

  5. SQL count和sum

    count(1).count(*)与count(列名)的执行区别 count(1) and count(字段) 两者的主要区别是 (1) count(1) 会统计表中的所有的记录数,包含字段为null ...

  6. MFC入门示例之组合框(CComboBox)、列表框(CListBox)

    1 //添加按钮点击事件 2 void CMFCApplication4Dlg::OnBnClickedButton1() 3 { 4 CString strText; 5 //获取文本框的值 6 G ...

  7. 3、Spring的DI依赖注入

    一.DI介绍 1.DI介绍 依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式称为注入. Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为&qu ...

  8. pycharm的破解和基本使用

    pycharm的破解 pycharm的账号注册 在完成安装后打开pycharm软件,需要选择购买或是使用.点击试用,选择进入官网注册账号. 进入官网后选择邮箱登录,输入自己的邮箱,点击sign up ...

  9. [BUUCTF]REVERSE——相册

    相册 附件 步骤: apk文件,习惯用apkide打开,看它反编译成了jar,就换jadx-gui打开,题目提示找邮箱,因此在导航栏里搜索mail 看到了sendMailByJavaMail(java ...

  10. Windwos堆管理体系以及溢出利用

    <0day安全>学习笔记,主要讨论WIndows2000~WIndowsSP1平台的堆管理策略. 0X01 堆与栈的区别 栈空间是在程序设计时已经规定好怎么使用,使用多少内存空间.典型的栈 ...