一位同事曾经告诉我,在Linux上一切都无法调试时,最后的选择是使用strace。
我试图学习这种奇怪工具背后的科学知识,但是我不是系统管理员,我并没有真正获得结果。
所以,
- 到底是什么,它做什么?
- 应该如何使用?在哪种情况下应使用?
- 应该如何理解和处理输出?
总之,在简单的话,怎么做这个东西的工作?
man strace
真的很容易阅读和有用。(PS昨天之前还不了解strace,而且不是Linux专家)
一位同事曾经告诉我,在Linux上一切都无法调试时,最后的选择是使用strace。
我试图学习这种奇怪工具背后的科学知识,但是我不是系统管理员,我并没有真正获得结果。
所以,
总之,在简单的话,怎么做这个东西的工作?
man strace
真的很容易阅读和有用。(PS昨天之前还不了解strace,而且不是Linux专家)
Answers:
Strace概述
strace可以看作是轻量级的调试器。它允许程序员/用户快速找出程序如何与OS交互。它通过监视系统调用和信号来做到这一点。
当您没有源代码或不想为真正的源代码而烦恼时,可以使用 Good。
另外,如果您不想打开GDB,而只是对了解外部交互感兴趣,则对您自己的代码很有用。
前
几天我对strace进行了介绍,这是一个很好的小介绍:strace hello world
ltrace
stackoverflow.com/a/52012215/5884955
-EFAULT
(哎呀,只读)缓冲区)或-ENOENT
(哎呀,从相对路径不起作用的错误目录中运行。)
简而言之,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
strace列出了由其应用到的进程完成的所有系统调用。如果您不知道系统调用的含义,那么您将无法从中获得很多收益。
但是,如果您的问题涉及文件,路径或环境值,则在有问题的程序上运行strace并将输出重定向到文件,然后将该文件grep为path / file / env字符串,可能会帮助您了解程序实际上在尝试执行什么操作与您的预期有所不同。
strace <prog_name>
跟踪程序。strace -o <out_file> <prog_name>
到了放一个文件
strace -e open myprog
OR对于所有与文件相关的系统调用:strace -e file myprog
Strace作为调查生产系统的工具而出类拔萃,您无法在调试器中运行这些程序。特别是,我们在以下两种情况下使用了strace:
有关使用strace分析的示例,请参阅我对这个问题的回答。
Strace可用作调试工具或原始分析器。
作为调试器,您可以查看给定系统调用的调用,执行方式以及返回的内容。这非常重要,因为它不仅使您可以看到程序失败,而且可以看到为什么程序失败。通常,这只是糟糕的编码导致无法捕获程序所有可能结果的结果。其他时候,它只是文件的硬编码路径。没有痕迹,您就可以猜测出哪里出问题以及怎么出问题了。使用strace可以得到系统调用的详细信息,通常仅查看返回值即可了解很多内容。
分析是另一种用途。您可以使用它来设置每个系统调用的执行时间,也可以作为一个整体。尽管这可能不足以解决您的问题,但至少会大大缩小潜在犯罪嫌疑人的范围。如果在单个文件上看到很多fopen / close对,则可能不必要在每次循环执行时打开和关闭文件,而不是在循环外部打开和关闭文件。
Ltrace是strace的近亲,也非常有用。您必须学会区分瓶颈所在。如果总执行时间为8秒,而您在系统调用上仅花费了0.05秒,那么跟踪程序并不能为您带来很多好处,问题出在您的代码中,这通常是逻辑问题,或者程序实际上需要花那么长时间才能运行。
strace / ltrace的最大问题是读取其输出。如果您不知道如何进行调用,或者至少不知道syscalls / functions的名称,那么将很难理解其含义。知道函数返回什么也将非常有益,特别是对于不同的错误代码。尽管很难破解,但有时它们确实会返回知识的明珠。一旦看到一种情况,我的索引节点用完了,但没有可用空间不足,因此所有常用的公用程序都没有给我任何警告,我只是无法制作一个新文件。从strace的输出中读取错误代码将我指向正确的方向。
Strace是一种工具,可以告诉您应用程序如何与操作系统交互。
它通过告诉您什么OS系统调用您的应用程序使用以及使用什么参数来实现此目的。
因此,例如,您看到了程序尝试打开的文件,并且成功进行了调用。
您可以使用此工具调试各种问题。例如,如果应用程序说它找不到您知道已安装的库,则strace会告诉您应用程序在哪里寻找该文件。
那只是冰山一角。
strace是学习程序如何进行各种系统调用(对内核的请求)以及报告失败的程序以及与该失败相关的错误值的好工具。并非所有故障都是错误。例如,尝试搜索文件的代码可能会收到ENOENT(没有这样的文件或目录)错误,但是在代码逻辑上可能是可以接受的情况。
使用strace的一个好用例是在临时文件创建期间调试竞争条件。例如,可能通过将进程ID(PID)附加到某些预定字符串来创建文件的程序在多线程方案中可能会遇到问题。[使用PID + TID(进程ID +线程ID)或更好的系统调用(例如mkstemp)可以解决此问题]。
这对于调试崩溃也很有用。您可能会发现有关strace和调试崩溃的这篇(我的)文章很有用。
最小的可运行示例
如果概念不清楚,那么您可能还没有看到一个更简单的示例来解释它。
在这种情况下,该示例是独立的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
组装并运行:
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
我们用:
env -i ASDF=qwer
控制环境变量:https : //unix.stackexchange.com/questions/48994/how-to-run-a-program-in-a-clean-environment-in-bash-s999 -v
在日志上显示更完整的信息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
write
line:显示我们进行的写入系统调用。6
是字符串的长度"hello\n"
。
= 6
是系统调用的返回值,如记录中man 2 write
所述,它是写入的字节数。
exit
line:显示我们进行的退出系统调用。由于程序已退出,因此没有返回值!
更复杂的例子
strace的应用程序当然是要查看复杂程序实际上在执行哪些系统调用来帮助调试/优化程序。
值得注意的是,您在Linux中可能会遇到的大多数系统调用都带有glibc包装器,其中许多来自POSIX。
在内部,glibc包装器或多或少使用内联汇编,如下所示:如何通过内联汇编中的sysenter调用系统调用?
您应该研究的下一个示例是POSIX write
hello world:
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中进行了测试。
这是一些我如何使用strace深入网站的示例。希望这会有所帮助。
像这样检查到第一个字节的时间:
time php index.php > timeTrace.txt
看看有多少百分比的动作在做什么。大量的lstat
和fstat
可能是一个迹象,是时候清除缓存:
strace -s 200 -c php index.php > traceLstat.txt
输出a,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
我喜欢其中的一些答案,这些答案可以strace
检查您如何与操作系统进行交互。
这正是我们所看到的。系统调用。如果比较strace
,ltrace
则差异更加明显。
$>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
但很可能是系统调用跟踪,因为这很明显。
有3个较大的注释要说strace
。
注意1:这两个函数strace
和ltrace
都在使用系统调用ptrace
。因此,ptrace
系统调用实际上是有效的strace
。
ptrace()系统调用提供了一种方法,一个进程(“跟踪程序”)可以通过它观察并控制另一进程(“跟踪”)的执行,并检查和更改该跟踪程序的内存和寄存器。它主要用于实现断点调试和系统调用跟踪。
注意2:可以使用多个不同的参数strace
,因为strace
它们可能很冗长。我喜欢尝试一下-c
,就像总结一下。根据-c
您可以选择一个系统调用,例如-e trace=open
您将只能看到该调用。如果要检查在跟踪命令期间将打开哪些文件,这可能会很有趣。当然,您可以将grep
用作相同的目的,但请注意,您需要像这样2>&1 | grep etc
进行重定向,以了解在发出命令时引用了配置文件。
注3:我发现这个非常重要的注解。您不限于特定的体系结构。strace
会让您大吃一惊,因为它可以跟踪不同体系结构的二进制文件。