291

一位同事曾经告诉我,当在 Linux 上调试一切都失败时,最后一个选择是使用strace

我试图学习这个奇怪工具背后的科学,但我不是系统管理员,我并没有真正得到结果。

所以,

  • 它到底是什么,它有什么作用?
  • 应该如何以及在哪些情况下使用它?
  • 应该如何理解和处理输出?

简而言之,简单来说,这些东西是如何工作的?

4

12 回答 12

196

Strace 概述
strace 可以看作是一个轻量级的调试器。它允许程序员/用户快速了解程序如何与操作系统交互。它通过监视系统调用和信号来做到这一点。


当您没有源代码或不想被打扰去真正阅读它时使用很好。
此外,如果您不想打开 GDB,但只想了解外部交互,这对您自己的代码很有用。

一个很好的小介绍
前几天我遇到了这个关于 strace 使用的介绍:strace hello world

于 2008-10-06T16:16:16.297 回答
65

简而言之,strace 跟踪程序发出的所有系统调用及其返回码。考虑诸如文件/套接字操作之类的事情以及更多晦涩的事情。

如果您对 C 有一定的应用知识,这是最有用的,因为这里的系统调用将更准确地代表标准 C 库调用。

假设您的程序是 /usr/local/bin/cough。只需使用:

strace /usr/local/bin/cough <any required argument for cough here>

或者

strace -o <out_file> /usr/local/bin/cough <any required argument for cough here>

写入“out_file”。

所有 strace 输出都将转到 stderr(请注意,它的庞大数量通常要求重定向到文件)。在最简单的情况下,您的程序将因错误而中止,您将能够在 strace 输出中看到它与操作系统的最后一次交互在哪里。

更多信息应通过以下方式获得:

man strace
于 2008-10-06T16:17:29.273 回答
38

strace 列出了它所应用的进程完成的所有系统调用。如果您不知道系统调用的含义,那么您将无法从中获得很多好处。

不过,如果您的问题涉及文件或路径或环境值,则在有问题的程序上运行 strace 并将输出重定向到文件,然后为您的路径/文件/env 字符串 grepping 该文件可能会帮助您查看程序实际尝试的内容做,与你所期望的不同。

于 2008-10-06T16:11:42.047 回答
19

Strace 是一种用于调查生产系统的工具,您无法在调试器下运行这些程序。特别是,我们在以下两种情况下使用了 strace:

  • 程序 foo 似乎处于死锁状态并且变得没有响应。这可能是 gdb 的目标;但是,我们并不总是拥有源代码,或者有时正在处理不能直接在调试器下运行的脚本语言。在这种情况下,您在已经运行的程序上运行 strace,您将获得正在执行的系统调用列表。如果您正在研究客户端/服务器应用程序或与数据库交互的应用程序,这将特别有用
  • 调查程序运行缓慢的原因。特别是我们刚刚迁移到一个新的分布式文件系统,系统的新吞吐量非常慢。您可以使用 '-T' 选项指定 strace,它会告诉您在每个系统调用中花费了多少时间。这有助于确定文件系统导致速度变慢的原因。

有关使用 strace 进行分析的示例,请参阅我对这个问题的回答。

于 2008-10-07T05:04:14.017 回答
16

我一直使用 strace 来调试权限问题。该技术是这样的:

$ strace -e trace=open,stat,read,write gnome-calculator

gnome-calculator您要运行的命令在哪里。

于 2015-05-04T15:33:22.080 回答
8

Strace 可以用作调试工具,也可以用作原始分析器。

作为调试器,您可以看到给定的系统调用是如何被调用、执行的以及它们返回什么。这非常重要,因为它不仅可以让您看到程序失败,还可以看到程序失败的原因。通常这只是糟糕的编码没有捕捉到程序的所有可能结果的结果。其他时候,它只是硬编码的文件路径。如果没有 strace,您就可以猜测出问题的地方和方式。使用 strace,您可以获得系统调用的细分,通常只需查看返回值即可告诉您很多信息。

剖析是另一种用途。您可以使用它来单独或作为聚合来计时每个系统调用的执行时间。虽然这可能不足以解决您的问题,但它至少会大大缩小潜在嫌疑人的范围。如果您在单个文件上看到很多 fopen/close 对,那么您可能在每次执行循环时都不必要地打开和关闭文件,而不是在循环之外打开和关闭它。

Ltrace 是 strace 的近亲,也非常有用。你必须学会​​区分你的瓶颈在哪里。如果总执行时间是 8 秒,而你只在系统调用上花费了 0.05 秒,那么跟踪程序对你没有多大好处,问题出在你的代码中,这通常是逻辑问题,或者程序实际上需要跑那么久。

strace/ltrace 最大的问题是读取它们的输出。如果您不知道调用是如何进行的,或者至少不知道系统调用/函数的名称,那么就很难理解其含义。了解函数返回的内容也非常有益,尤其是对于不同的错误代码。虽然破译很痛苦,但它们有时真的会返回一颗知识的珍珠;一旦我看到我的 inode 用完了,但没有用完可用空间,因此所有常用的实用程序都没有给我任何警告,我就是无法创建新文件。从 strace 的输出中读取错误代码为我指明了正确的方向。

于 2009-08-03T18:21:55.877 回答
8

strace -tfp PID 将监控 PID 进程的系统调用,因此我们可以调试/监控我们的进程/程序状态。

于 2014-06-19T14:44:31.823 回答
7

最小可运行示例

如果一个概念不清楚,有一个你没见过的更简单的例子来解释它。

在本例中,该示例是 Linux x86_64 程序集独立式(无 libc)hello world:

你好.S

.text
.global _start
_start:
    /* write */
    mov $1, %rax    /* syscall number */
    mov $1, %rdi    /* stdout */
    mov $msg, %rsi  /* buffer */
    mov $len, %rdx  /* buffer len */
    syscall

    /* exit */
    mov $60, %rax   /* exit status */
    mov $0, %rdi    /* syscall number */
    syscall
msg:
    .ascii "hello\n"
len = . - msg

GitHub 上游.

组装并运行:

as -o hello.o hello.S
ld -o hello.out hello.o
./hello.out

输出预期:

hello

现在让我们在该示例中使用 strace:

env -i ASDF=qwer strace -o strace.log -s999 -v ./hello.out arg0 arg1
cat strace.log

我们用:

strace.log现在包含:

execve("./hello.out", ["./hello.out", "arg0", "arg1"], ["ASDF=qwer"]) = 0
write(1, "hello\n", 6)                  = 6
exit(0)                                 = ?
+++ exited with 0 +++

有了这样一个最小的例子,输出的每一个字符都是不言而喻的:

  • execve行:显示如何strace执行hello.out,包括 CLI 参数和环境,如记录在man execve

  • writeline:显示了我们所做的 write 系统调用。6是字符串的长度"hello\n"

    = 6是系统调用的返回值,如中所述,它man 2 write是写入的字节数。

  • exitline: 显示我们所做的退出系统调用。没有返回值,因为程序退出了!

更复杂的例子

strace的应用当然是看复杂程序实际做了哪些系统调用来帮助调试/优化你的程序。

值得注意的是,您可能在 Linux 中遇到的大多数系统调用都有 glibc 包装器,其中许多来自 POSIX

在内部,glibc 包装器或多或少像这样使用内联汇编:How to invoke a system call via sysenter in inline assembly?

您应该学习的下一个示例是 POSIX writehello world:

主程序

#define _XOPEN_SOURCE 700
#include <unistd.h>

int main(void) {
    char *msg = "hello\n";
    write(1, msg, 6);
    return 0;
}

编译并运行:

gcc -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out

这一次,您将看到 glibc 之前main进行了一系列系统调用,以便为 main 设置一个良好的环境。

这是因为我们现在使用的不是独立程序,而是更常见的 glibc 程序,它允许 libc 功能。

然后,在每一端,strace.log包含:

write(1, "hello\n", 6)                  = 6
exit_group(0)                           = ?
+++ exited with 0 +++

因此我们得出结论,writePOSIX 函数使用了 Linuxwrite系统调用,令人惊讶!

我们还观察到return 0导致exit_group调用而不是exit. 哈,我不知道这个!这就是为什么strace这么酷。man exit_group然后解释:

这个系统调用等价于 exit(2),除了它不仅终止调用线程,而且终止调用进程的线程组中的所有线程。

这是我研究使用哪个系统调用的另一个示例dlopenhttps ://unix.stackexchange.com/questions/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

在 Ubuntu 16.04、GCC 6.4.0、Linux 内核 4.4.0 中测试。

于 2019-03-28T12:07:01.997 回答
4

Strace 是一个工具,可以告诉您应用程序如何与操作系统交互。

它通过告诉您应用程序使用的操作系统系统调用以及调用它们的参数来做到这一点。

因此,例如,您会看到程序尝试打开哪些文件,并判断调用是否成功。

您可以使用此工具调试各种问题。例如,如果应用程序说它找不到您知道已安装的库,那么 strace 会告诉您应用程序在哪里寻找该文件。

而这只是冰山一角。

于 2008-10-06T16:22:19.607 回答
4

strace 是一个很好的工具,用于了解您的程序如何进行各种系统调用(对内核的请求),并且还报告失败的系统调用以及与该失败相关的错误值。并非所有的失败都是错误。例如,尝试搜索文件的代码可能会收到 ENOENT(没有此类文件或目录)错误,但这可能是代码逻辑中可接受的场景。

使用 strace 的一个很好的用例是在临时文件创建期间调试竞争条件。例如,可能通过将进程 ID (PID) 附加到某些预先确定的字符串来创建文件的程序在多线程场景中可能会遇到问题。[PID+TID(进程 ID + 线程 ID)或更好的系统调用,如 mkstemp 将解决此问题]。

它也适用于调试崩溃。您可能会发现这篇(我的)关于 strace 和调试崩溃的文章很有用。

于 2009-08-03T17:27:28.500 回答
4

以下是我如何使用 strace 挖掘网站的一些示例。希望这会有所帮助。

检查第一个字节的时间,如下所示:

time php index.php > timeTrace.txt

看看有多少百分比的动作在做什么。很多lstat并且fstat可能表明是时候清除缓存了:

strace -s 200 -c php index.php > traceLstat.txt

输出 atrace.txt这样您就可以准确地看到正在进行的调用。

strace -Tt -o Fulltrace.txt php index.php

使用它来检查是否有任何东西需要.1.9秒钟才能加载:

cat Fulltrace.txt | grep "[<]0.[1-9]" > traceSlowest.txt

查看strace. 这将输出很多涉及我们系统的内容——唯一相关的部分涉及客户的文件:

strace -vv php index.php 2>&1 | sed -n '/= -1/p' > traceFailures.txt
于 2019-09-17T13:34:05.527 回答
1

我喜欢其中一些答案,它读取strace检查您如何与操作系统交互。

这正是我们可以看到的。系统调用。如果对比一下straceltrace差别就更明显了。

$>strace -c cd
Desktop  Documents  Downloads  examples.desktop  Music  Pictures  Public  Templates  Videos
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         7           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0        11           close
  0.00    0.000000           0        10           fstat
  0.00    0.000000           0        17           mmap
  0.00    0.000000           0        12           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         2           ioctl
  0.00    0.000000           0         8         8 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         2           getdents
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         9           openat
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         1           prlimit64
------ ----------- ----------- --------- --------- ----------------
100.00    0.000000                    93        10 total

另一方面是ltrace跟踪功能。

$>ltrace -c cd
Desktop  Documents  Downloads  examples.desktop  Music  Pictures  Public  Templates  Videos
% time     seconds  usecs/call     calls      function
------ ----------- ----------- --------- --------------------
 15.52    0.004946         329        15 memcpy
 13.34    0.004249          94        45 __ctype_get_mb_cur_max
 12.87    0.004099        2049         2 fclose
 12.12    0.003861          83        46 strlen
 10.96    0.003491         109        32 __errno_location
 10.37    0.003303         117        28 readdir
  8.41    0.002679         133        20 strcoll
  5.62    0.001791         111        16 __overflow
  3.24    0.001032         114         9 fwrite_unlocked
  1.26    0.000400         100         4 __freading
  1.17    0.000372          41         9 getenv
  0.70    0.000222         111         2 fflush
  0.67    0.000214         107         2 __fpending
  0.64    0.000203         101         2 fileno
  0.62    0.000196         196         1 closedir
  0.43    0.000138         138         1 setlocale
  0.36    0.000114         114         1 _setjmp
  0.31    0.000098          98         1 realloc
  0.25    0.000080          80         1 bindtextdomain
  0.21    0.000068          68         1 opendir
  0.19    0.000062          62         1 strrchr
  0.18    0.000056          56         1 isatty
  0.16    0.000051          51         1 ioctl
  0.15    0.000047          47         1 getopt_long
  0.14    0.000045          45         1 textdomain
  0.13    0.000042          42         1 __cxa_atexit
------ ----------- ----------- --------- --------------------
100.00    0.031859                   244 total

虽然我查了几次手册,但我没有找到名称的来源,strace但很可能是系统调用跟踪,因为这很明显。

有三个更大的注意事项要说strace

注1:这两个函数straceltrace使用系统调用ptrace。所以ptrace系统调用是有效的strace工作方式。

ptrace() 系统调用提供了一种方法,一个进程(“跟踪器”)可以通过该方法观察和控制另一个进程(“跟踪者”)的执行,并检查和更改跟踪者的内存和寄存器。主要用于实现断点调试和系统调用跟踪。

注意 2:您可以使用不同的参数strace,因为strace可能非常冗长。我喜欢实验,-c这就像对事物的总结。根据-c您可以选择一个系统调用,例如-e trace=open您只会看到该调用的位置。如果您正在检查在您正在跟踪的命令期间将打开哪些文件,这可能会很有趣。当然,您可以将grep用于相同目的,但请注意,您需要像这样重定向2>&1 | grep etc以了解在发出命令时引用了配置文件。

注意 3:我发现这个非常重要的注释。您不限于特定的架构。strace会让你大吃一惊,因为它可以追踪不同架构的二进制文件。 在此处输入图像描述

于 2018-08-24T21:59:42.073 回答