Strace——隐藏的超能力

2023-12-18 17:09:22 浏览数 (1)

与任何操作系统一样,在运行 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 的开源基础,提供您可能无法获得的见解。

0 人点赞