与任何操作系统一样,在运行 Linux 和相关应用程序时遇到问题并不罕见。在使用闭源程序时尤其如此,因为无法进行精细的代码检查。
与任何操作系统一样,在运行 Linux 和相关应用程序时遇到问题并不罕见。在使用闭源程序时尤其如此,因为无法进行精细的代码检查。因此,排除故障和解决问题并不是一个简单的过程。Linux 管理员和工程师很快发现需要补充实用程序。值得庆幸的是,他们并没有等太久。
Strace 在 Linux 之后不久推出,旨在解决其中的许多问题。正如官方网站所述,正式称为 Linux 系统调用调用程序,“Strace 是 Linux 的诊断、调试和指导用户空间实用程序”。您可以使用 Strace 来监督和操作进程如何与 Linux 内核交互。这包括:
- 系统调用
- 进程状态变化
- 信号传输
因此,该实用程序还可以帮助您解决自己的应用程序的问题。此类应用程序经常与其他资源进行外部交互,因此了解这些机制至关重要。Linux 内核的“ptrace”功能最终使 Strace 发挥其魔力。创建“ptrace”本身是为了促进系统调用跟踪和断点调试。
Strace 至今仍保持开源状态。存储库位于 GitHub 和 GitLab 中,并且还提供二进制包通过各种来源。Strace 的开发节奏更加谨慎,但其开发人员仍在继续推出新版本。
本介绍指南深入探讨了 Strace 及其用例、使用说明以及最佳实践。
为什么选择 Strace——考虑因素及更多
首先,了解 Strace 的功能和局限性是很有好处的。虽然该工具提供了大量有用的功能,但它并不意味着能够处理所有可以想象到的 Linux 故障排除过程。在 Strace 自己的文档中,明确指出了以下操作:
- 附加到正在运行的进程
- 打印与文件描述符相关的路径和详细信息
- 按系统调用类型过滤
- 仅通过特定路径跟踪系统调用
- 对从文件描述符读取/写入的所有数据执行完整的十六进制和 ASCII 转储
- 执行系统调用执行注入
- 计算系统调用总时间、调用和错误
使用 Strace 的复杂性可能有很大差异。您可以在 Linux CLI 中输入简短的一行命令并运行它,直到退出。相反,十六进制数据转储等操作可能需要输入大量特定参数、属性等。当然,这些命令可能需要更多时间来执行,因此更容易出错。
Strace 拦截并记录源自特定进程及其相关信号的系统调用。结果,Strace 打印任何关联的参数并将值返回到两个不同的目的地:标准错误或预定文件。您可以通过键入“-o”选项并输入文件路径来指定此文件名。
使用 Strace 可以轻松跟踪独立进程;但是,您可能会注意到,Strace 无法捕获命令执行期间您期望的所有信息。这就是子进程发挥作用的地方。您正在跟踪的父进程可能有多个与其关联的辅助进程。值得庆幸的是,您可以通过“-f”选项捕获这些子进程,同时附加您的程序名称。
strace 语法
Strace 和 Linux CLI 在每个 Strace 命令中利用多个运算符。这些选项有不同的用途,因此您可以使用它们来执行非常具体的操作。以下是一些常见的 Strace 命令构建块,称为 选项:
- [-I n] – 指定可中断信号
- [-b execve] – 用于从指定的系统调用分离或跟踪多线程进程
- [-e expr] – 修改要跟踪的事件或跟踪方式跟踪它们
- [-O overhead] – 设置跟踪系统调用的开销
- [-S sortby] – 按特定标准对打印的直方图进行排序
- [-U columns] – 配置顺序和显示的列集
- [-a column] – 对齐特定列中的返回值
- [-o file] – 指定打印目标
- [-s strsize] – 指定可打印的最大数量字符串大小
- [-X format] – 设置打印、命名常量和标志的格式
- [-P path] – 仅跟踪访问给定路径的调用
- [-p pid] –附加到指定进程 ID 并开始跟踪
- [-E var=[val]] – 使用环境变量列表中给定的 var=val 运行命令
- [-u username] – 运行命令具有用户 ID、组 ID 或补充组
每个括号内的斜体部分代表一个值或限定符,帮助 Strace 理解它应该做什么。这不是 Strace 命令和语法的详尽列表(在 选项 部分下找到此处),但它提供了以下内容的快照您可以利用一些基本功能。
还有一些关键系统调用您还应该熟悉:
- read– 从文件描述符中读取字节
- write– 从文件描述符写入字节
- open– 打开文件并返回描述符
- close– 关闭文件描述符
- fork– 创建一个新进程,同时分叉当前进程
- exec– 执行一个新程序
- connect– 连接到网络主机
- accept– 接受网络连接
- stat– 读取文件统计信息
- ioctl– 设置 I/O 属性或其他功能
- mmap– 将文件映射到进程内存地址空间
- brk– 扩展堆指针
主要要点是:即使利用这些基本列表中的信息,您仍然可以使用 Strace 执行大量操作。可用的调用和选项列表非常庞大,它们的功能涉及大多数应用程序或操作系统元素。
Linux CLI 在您的命令下以人类可读的格式发出响应;然而,这些响应的复杂性和长度可能相差很大。Strace 的输出数据量可能是压倒性的。
那些熟悉 Linux CLI 的人(如果您正在陷入这个兔子洞,建议您这样做)可以使用“echo”属性来促进更好的间距和整体格式。您可以指示 Strace 输出到标准输出而不是标准错误。
Strace 的缺点
了解 Strace 与您的应用程序和底层系统交互的深度非常重要。从操作系统的角度来看,您主要在“用户模式”下操作 - 命令行和 GUI 元素是正常使用期间执行的任何操作的基础;然而,当引入系统调用时,情况会变得有点复杂。这些调用在后台进行更深层次的操作,直接与 Linux 内核交互。默认情况下,系统调用享有更高的权限,并对系统性能产生巨大影响。
正如您想象的那样,打断、操纵和拨打新电话可能会影响当前通话。Strace 会暂停每个系统调用的目标进程两次,以对其进行正确分析。在这些情况下,Strace 读取并记录进程状态。不幸的是,如果大量使用这些操作,可能会频繁地暂停您的应用程序。因此,还会发生持续的上下文切换,从而在系统切换时增加执行时间。
因此,Strace 的性能开销会根据相关系统调用而变化。不幸的是,将 Strace 添加到现有系统调用中可能会使它们的执行时间变得相对缓慢。这可能会出现问题,具体取决于您的工作流程。最近的 Strace 迭代有助于减轻这些性能损失,尽管它仍然值得考虑。
示例 Strace 调用
下面是一个简单的 Strace 命令示例,您可以将 Strace 附加到当前正在运行的进程:
代码语言:javascript复制$ strace -p 1267
您的输出确认该命令已执行,并显示 Strace 现在已“安装”相关进程:
代码语言:javascript复制strace: Process 1267 attached
这是使用 Strace 时可能看到的最简单的输出之一。或者,如果您执行诸如 count 命令之类的操作,CLI 将显示一个包含上下文结果的表格:
因此,Strace 的输出差异很大,但虽然对于新手来说并不总是很容易理解,但它们很容易解释。运行程序命令非常相似,并且利用前面提到的多个系统调用之一。如果您只想打印打开的系统调用怎么办?只需在 PID 属性中输入目标进程 ID 即可启动进程:
代码语言:javascript复制$ strace -eopen -p PID
Strace 使用场景
总体而言,Strace 可能是在测试环境中使用的最佳或“最负责任”的方法。在这些情况下,性能和命令安全性并不重要,特别是因为您不会因中断而影响应用程序用户。Strace 的包装器和输出可以提供大量的故障排除信息。
Strace 的动态性能开销可能会给生产环境带来一些不确定性。超过延迟阈值可能会导致目标故障转移。也就是说,Strace 在某些生产场景中可能至关重要。就像混沌测试需要一定程度的实时用户实验来发现问题一样,当应用程序被沙箱化时,正确解决问题可能是不可能的。
结论
在正确的场景中,Strace 显然是一个非常有用的调试和故障排除工具。它可以帮助您更深入地了解您的应用程序以及它在运行时如何与 Linux 内核交互。这种透明度也延伸到第三方应用程序。
Strace 并非在所有情况下都是完美的。然而,它的灵活性吸引了经验丰富的管理员。总体而言,Strace 有助于构建 Linux 的开源基础,提供您可能无法获得的见解。