怎么应该使用strace?

时间:2008-10-06 16:07:41

标签: linux debugging strace

一位同事曾告诉我,在Linux上无法调试的最后一个选项是使用strace

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

所以,

  • 究竟是什么,它做了什么?
  • 应该如何以及在何种情况下使用它?
  • 如何理解和处理输出?

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

12 个答案:

答案 0 :(得分:178)

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

<强>用途
当你没有源代码或不想被打扰时,这对你有好处 此外,如果您不想打开GDB,但只想了解外部交互,那么对您自己的代码很有用。

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

答案 1 :(得分:60)

简单来说,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输出中与OS的最后交互位置。

应提供更多信息:

man strace

答案 2 :(得分:34)

strace列出了应用它的进程完成的所有系统调用。如果您不知道系统调用的意思,您将无法获得更多的里程数。

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

答案 3 :(得分:15)

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

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

有关使用strace进行分析的示例,请参阅我对this question的回答。

答案 4 :(得分:15)

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

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

其中gnome-calculator是您要运行的命令。

答案 5 :(得分:7)

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

答案 6 :(得分:6)

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

作为调试器,您可以看到如何调用,执行给定的系统调用以及它们返回的内容。这非常重要,因为它不仅可以让您看到程序失败,还可以看到程序失败的原因。通常,这只是糟糕的编码没有捕捉到程序的所有可能结果的结果。其他时候它只是文件的硬编码路径。没有strace,你可以猜到在哪里以及如何出错。使用strace,您可以获得系统调用的细分,通常只是查看返回值会告诉您很多。

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

Ltrace是strace的近亲,也非常有用。你必须学会​​区分你的瓶颈所在。如果总执行时间为8秒,并且您在系统调用上只花费了0.05秒,那么对程序进行支持并不会对您有好处,问题在于您的代码,这通常是一个逻辑问题,或者程序实际需要花那么长时间才能跑。

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

答案 7 :(得分:4)

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

它通过告诉您应用程序使用的OS系统调用以及调用它们的参数来实现此目的。

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

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

这只是冰山一角。

答案 8 :(得分:4)

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

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

它也适用于调试崩溃。您可能会发现this (my) article on strace and debugging crashes有用。

答案 9 :(得分: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会让您大吃一惊,因为它可以跟踪不同体系结构的二进制文件。 enter image description here

答案 10 :(得分:1)

这是一些我如何使用strace来深入研究网站的示例。希望这会有所帮助。

像这样检查到第一个字节的时间:

time php index.php > timeTrace.txt

查看正在执行操作的百分比。许多lstatfstat可能表明该清除缓存了:

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

输出trace.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

答案 11 :(得分:0)

最小的可运行示例

如果概念不清楚,那么您可能还没有看到一个更简单的示例来解释它。

在这种情况下,该示例是独立的Linux x86_64程序集(无libc)的hello世界:

你好。

.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 upstream

组装并运行:

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,包括man execve

  • 中记录的CLI参数和环境。
  • write行:显示我们进行的写入系统调用。 6是字符串"hello\n"的长度。

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

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

更复杂的示例

strace的应用程序当然是要查看复杂程序实际上正在执行哪些系统调用来帮助调试/优化程序。

值得注意的是,您在Linux中可能会遇到的大多数系统调用都有glibc包装器many of them from POSIX

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

您应该研究的下一个示例是POSIX write你好世界:

main.c

#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 +++

因此我们得出结论,write POSIX函数使用Linux write系统调用令人惊讶!

我们还观察到return 0导致了exit_group而不是exit的呼叫。哈,我不知道这件事!这就是strace如此酷的原因。 man exit_group然后解释:

  

此系统调用等效于exit(2),不同之处在于它不仅终止调用线程,而且终止调用进程的线程组中的所有线程。

这是另一个示例,我研究了dlopen使用哪个系统调用:https://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中进行了测试。