一位同事曾经告诉我,当Linux上所有调试都失败时,最后的选择是使用strace。
我试图学习这个奇怪工具背后的科学,但我不是系统管理专家,我没有真正得到结果。
So,
它到底是什么,有什么作用? 如何以及在哪些情况下使用它? 应该如何理解和处理输出?
简而言之,简单地说,这东西是怎么工作的?
一位同事曾经告诉我,当Linux上所有调试都失败时,最后的选择是使用strace。
我试图学习这个奇怪工具背后的科学,但我不是系统管理专家,我没有真正得到结果。
So,
它到底是什么,有什么作用? 如何以及在哪些情况下使用它? 应该如何理解和处理输出?
简而言之,简单地说,这东西是怎么工作的?
当前回答
Strace概述 Strace可以看作是一个轻量级调试器。它允许程序员/用户快速发现程序是如何与操作系统交互的。它通过监控系统调用和信号来做到这一点。
使用 当你没有源代码或者不想被打扰去真正浏览它的时候,这很好。 此外,如果您不喜欢打开GDB,而只是对理解外部交互感兴趣,那么对于您自己的代码也很有用。
这是一个很好的介绍 下面是一个使用strace来调试进程挂起的温和介绍
其他回答
简单地说,strace跟踪程序发出的所有系统调用及其返回码。想想诸如文件/套接字操作和许多更模糊的操作。
如果你有一些C的工作知识,这是最有用的,因为这里的系统调用更准确地代表标准C库调用。
假设您的程序是/usr/local/bin/cough。简单的使用方法:
strace /usr/local/bin/cough <any required argument for cough here>
or
strace -o <out_file> /usr/local/bin/cough <any required argument for cough here>
写入'out_file'。
所有strace输出都将转到stderr(注意,它的巨大容量通常要求重定向到文件)。在最简单的情况下,您的程序将因错误而中止,您将能够在strace输出中看到它与操作系统的最后一次交互。
如欲获得更多资料,请浏览:
man strace
我喜欢一些答案,它读取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的起源,但它可能是系统调用跟踪,因为这是显而易见的。
关于strace有三个更重要的说明。
注1:strace和ltrace这两个函数都使用了系统调用ptrace。所以ptrace系统调用是strace有效工作的方式。
ptrace()系统调用提供了一种方法,通过这种方法,一个进程 “跟踪程序”)可以观察和控制另一个进程的执行 (“被追踪者”),检查和改变被追踪者的记忆和 寄存器。它主要用于实现断点调试 以及系统调用跟踪。
Note 2: There are different parameters you can use with strace, since strace can be very verbose. I like to experiment with -c which is like a summary of things. Based on -c you can select one system-call like -e trace=open where you will see only that call. This can be interesting if you are examining what files will be opened during the command you are tracing. And of course, you can use the grep for the same purpose but note you need to redirect like this 2>&1 | grep etc to understand that config files are referenced when the command was issued.
注3:我发现这一点非常重要。您不局限于特定的体系结构。Strace会让你大吃一惊,因为它可以跟踪不同体系结构的二进制文件。
最小可运行示例
如果一个概念不清楚,有一个你没有见过的更简单的例子可以解释它。
在本例中,这个例子是Linux x86_64程序集独立(无libc) hello world:
你好。年代
.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
我们使用:
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 +++
在这样一个最小的例子中,输出的每个字符都是不言而喻的:
执行行:显示strace如何执行hello。包括CLI参数和man execve中记录的环境 写行:显示我们所做的写系统调用。6是字符串“hello\n”的长度。 = 6是系统调用的返回值,在man 2 write中记录的是写入的字节数。 退出行:显示我们所做的退出系统调用。没有返回值,因为程序退出了!
更复杂的例子
当然,strace的应用是为了查看复杂程序实际上执行了哪些系统调用,以帮助调试/优化程序。
值得注意的是,您在Linux中可能遇到的大多数系统调用都有glibc包装器,其中许多来自POSIX。
在内部,glibc包装器或多或少像这样使用内联汇编:如何在内联汇编中通过sysenter调用系统调用?
你应该学习的下一个例子是POSIX write hello world:
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 +++
因此我们得出结论,写POSIX函数使用,惊喜!, Linux写系统调用。
我们还观察到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 -tfp PID将监控PID进程的系统调用,因此我们可以调试/监控我们的进程/程序状态。
Strace概述 Strace可以看作是一个轻量级调试器。它允许程序员/用户快速发现程序是如何与操作系统交互的。它通过监控系统调用和信号来做到这一点。
使用 当你没有源代码或者不想被打扰去真正浏览它的时候,这很好。 此外,如果您不喜欢打开GDB,而只是对理解外部交互感兴趣,那么对于您自己的代码也很有用。
这是一个很好的介绍 下面是一个使用strace来调试进程挂起的温和介绍