首页
社区
课程
招聘
[原创]strace是啥?strace怎么用?
发表于: 2022-1-7 22:16 22109

[原创]strace是啥?strace怎么用?

2022-1-7 22:16
22109

这一篇文章会介绍strace如何工作,再稍微深入介绍一下什么是system call。再介绍一下ptrace、wait(strace依赖的system call)。最后再一起来造个轮子,动手用代码实现一个strace。聊天框回复“strace”,可以获取本文源码。

上一篇,我们介绍了strace工具,strace是非常实用的调试、分析工具,可以记录process调用system call的参数、返回值。

效果展示
下面展示一下我们实现简化版的strace的效果,每行打印一个system call。只不过没有根据system call的序号转换参数类型来打印,毕竟我们实现的目的是学习。

上一篇,我们简单介绍了系统调用(system call)。strace就是记录system call的工具,我们需要深入了解一下system call。

每个system call都有一个序号,记录在/usr/include/x86_64-linux-gnu/asm/unistd_64.h文件中。我们常见的read、write、open都在其中定义。

我们可以调用glibc封装的system call(例如close、connect、bind等),还可以使用syscall直接调用。glibc中的封装最终也是调用了syscall。

例如我们调用tgkill时

我们可以使用glibc封装的

也可以使用syscall直接传system call 序号和对于参数来调用。

我们需要了解一下调用syscall时,用户层与内核是交互交互返回值和参数的。

根据man syscall手册。不同的cpu通过不同寄存器来传递。

返回值:

x86-64位下,返回值在rax寄存器。

参数列表:

x86-64位下,参数依次是rdi rsi rdx r10 r8 r9。

首先介绍我们把tracer和tracee的概念:我们把跟踪者(strace)叫做tracer,被跟踪process叫做tracee。

strace整体工作流程如下:

磨刀不误砍柴工,我们也来介绍一下strace工作时两个重要函数。

通过上面流程图,可以看出strace在建立trace关系、跟踪system call时都依赖ptrace。

man ptrace

man手册是这么描述的:ptrace可以让tracer观察并控制tracee的执行,并可以获取并修改tracee的内存和寄存器。可以用来实现调试器或system call跟踪。实际上gdb和strace都是依赖ptrace来实现的。

参数

wait也是strace工作时也很重要,先看看man手册。

man wait

man手册是这么描述的:wait用来等待子进程状态改变,包括退出、stopped、resumed。
如果子进程状态已经改变了,wait会立刻返回。否则会卡住等待状态改变。

状态通过wstatus返回,wait也提供了一系列配套宏来判断状态。

strace使用wait有2个场景:

strace工作的第一步就是建立trace关系,按照不同启动模式采取不同的方式建立。无论是哪种模式,都需要与tracee建立trace关系。才能监控system call的调用。

strace的启动模式:

attach模式建立trace关系
strace调用ptrace(request=PTRACE_ATTACH)与tracee建立trace关系。

strace启动模式建立trace关系
此模式下,strace需要先执行fork。然后父进程作为tracer,子进程作为tracee。

子进程fork以后,还需要执行ptrace(request=PTRACE_TRACEME)来建立trace关系。

建立好trace关系以后,子进程还需要调用execv来执行tracee的逻辑。

代码
无论是attach模式还是strace启动模式,建立trace关系后,都执行相同的逻辑,代码可以复用。

建立trace关系后,strace需要调用wait,来等待tracer变为stop状态。

xx_waitstate2str是封装好,打印子进程状态的

屏幕输出

建立好trace关系后,tracee是处于stop状态的。下一步开始循环跟踪tracee的system call。

strace使用ptrace 跟踪tracee的system call时会有两次拦截,一次是调用前,一次是调用完成后。

调用前拦截时,有以下操作:

调用前拦截时,system call还没被调用,通过寄存器信息,可以获取:

调研后拦截时,system call已调用完毕。通过寄存器可以获取返回值,以及调用后的参数。前面1.3章节介绍了system call在不同cpu架构使用哪些寄存器。

下面我们来看看代码实现.

步骤1(唤醒)、2(等待)
我们封装了一个函数

循环跟踪主题
循环主题主要就是两次拦截、获取信息、打印信息。

保存system call信息

调用前拦截、获取system call序号

调用后拦截、获取参数、返回值

不足200行代码,实现了strace基础功能。造个轮子能更好的学习,大家学会了么?

最后,“东北码农”  求微信关注、点赞、转发,谢谢~
求关注

求关注


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//