Linux Command strace 调试跟踪(1)

简介: Linux Command strace 调试跟踪(1)

Linux Command strace 调试跟踪

tags: 分析,进程

文章目录

Linux Command strace 调试跟踪

1. strace 是什么?

2. strace 能做什么?

3. strace 怎么用?

3.1 系统调用

3.2 strace 常用选项

3.3 常见命令

4. 两种运行模式。

4.1 一种是通过它启动要跟踪的进程。

4.2 另一种是跟踪已经在运行的进程

5. strace 问题定位案例

.51 定位进程异常退出

5.2 定位共享内存异常

5.3 性能分析

5.4 strace 对进程的性能影响

5.5 strace 调试连接问题

1. strace 是什么?

按照strace官网的描述, strace是一个可用于诊断、调试和教学的Linux用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。


strace底层使用内核的ptrace特性来实现其功能。


在运维的日常工作中,故障处理和问题诊断是个主要的内容,也是必备的技能。strace作为一种动态跟踪工具,能够帮助运维高效地定位进程和服务故障。它像是一个侦探,通过系统调用的蛛丝马迹,告诉你异常的真相。

1832b220aa754cd18c504acc7686a560.png

2. strace 能做什么?

运维工程师都是实践派的人,我们还是先来个例子吧。

我们从别的机器copy了个叫做some_server的软件包过来,开发说直接启动就行,啥都不用改。可是尝试启动时却报错,根本起不来!

启动命令:

./some_server ../conf/some_server.conf

输出:

FATAL: InitLogFile failed iRet: -1!
Init error: -1655

为什么起不来呢?从日志看,似乎是初始化日志文件失败,真相到底怎样呢?我们用strace来看看。

strace -tt -f  ./some_server ../conf/some_server.conf

输出:

我们注意到,在输出InitLogFile failed错误的前一行,有个open系统调用:

23:14:24.448034 open("/usr/local/apps/some_server/log//server_agent.log", O_RDWR|O_CREAT|O_APPEND|O_LARGEFILE, 0666) = -1 ENOENT (No such file or directory)

尝试打开文件/usr/local/apps/some_server/log//server_agent.log来写(不存在则创建),可是却出错了,返回码是-1, 系统错误号errorno为ENOENT。 查下open系统调用的手册页:

man 2 open

搜索ENOENT这个错误号errno的解释

ENOENT O_CREAT  is not set and the named file does not exist.  Or, a directory component in pathname does not exist or is a dangling symbolic link.

这里说得比较清楚,因为我们例子中的open选项指定了O_CREAT选项,这里errno为ENOENT的原因是日志路径中某个部分不存在或者是一个失效的符号链接。我们来一级一级看下路径中的哪部分不存在:

ls -l /usr/local/apps/some_server/log
ls: cannot access /usr/local/apps/some_server/log: No such file or directory
ls -l /usr/local/apps/some_server
total 8
drwxr-xr-x 2 root users 4096 May 14 23:13 bin
drwxr-xr-x 2 root users 4096 May 14 22:48 conf

原来是log子目录不存在!上层目录都是存在的。手工创建log子目录后,服务就能正常启动了。

回过头来, strace究竟能做什么呢?

它能够打开应用进程的这个黑盒,通过系统调用的线索,告诉你进程大概在干嘛。

3. strace 怎么用?

既然strace是用来跟踪用户空间进程的系统调用和信号的,在进入strace使用的主题之前,我们的先理解什么是系统调用。

3.1 系统调用

按维基百科中的解释,在计算机中,系统调用(英语:system call),又称为系统呼叫,指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。


系统调用提供用户程序与操作系统之间的接口。操作系统的进程空间分为用户空间和内核空间:


操作系统内核直接运行在硬件上,提供设备管理、内存管理、任务调度等功能。

用户空间通过API请求内核空间的服务来完成其功能——内核提供给用户空间的这些API, 就是系统调用。

在Linux系统上,应用代码通过glibc库封装的函数,间接使用系统调用。

Linux内核目前有300多个系统调用,详细的列表可以通过syscalls手册页查看。这些系统调用主要分为几类:


文件和设备访问类 比如open/close/read/write/chmod等

进程管理类 fork/clone/execve/exit/getpid等

信号类 signal/sigaction/kill 等

内存管理 brk/mmap/mlock等

进程间通信IPC shmget/semget * 信号量,共享内存,消息队列等

网络通信 socket/connect/sendto/sendmsg 等

熟悉Linux系统调用/系统编程,能够让我们在使用strace时得心应手。不过,对于运维的问题定位来说,知道strace这个工具,会查系统调用手册,就差不多够了。


常见的系统调用:


Open() - 用于打开或创建文件的系统调用

Read() — 用于读取文件的系统调用

Write( ) — 用于写入文件的系统调用

Connect() — 用于打开与其他应用程序/网站/等的连接的系统调用。

futex() — 用于强制程序等待条件为真或在内存中实现锁定的系统调用

想要深入了解的同学,建议阅读《Linux系统编程》, 《Unix环境高级编程》等书籍。

3.2 strace 常用选项

strace -tt -T -v -f -e trace=file -o /data/log/strace.log -s 1024 -p 23489
-tt 在每行输出的前面,显示毫秒级别的时间
-T 显示每次系统调用所花费的时间
-v 对于某些相关调用,把完整的环境变量,文件stat结构等打出来。
-f 跟踪目标进程,以及目标进程创建的所有子进程
-e 控制要跟踪的事件和跟踪行为,比如指定要跟踪的系统调用名称
-o 把strace的输出单独写到指定的文件
-s 当系统调用的某个参数是字符串时,最多输出指定长度的内容,默认是32个字节
-p 指定要跟踪的进程pid, 要同时跟踪多个pid, 重复多次-p选项即可。

实例:跟踪nginx, 看其启动时都访问了哪些文件

strace -tt -T -f -e trace=file -o /data/log/strace.log -s 1024 ./nginx

3.3 常见命令

# Slow the target command and print details for each syscall:
strace command
# Slow the target PID and print details for each syscall:
strace -p PID
# Slow the target PID and any newly created child process, printing syscall details:
strace -fp PID
# Slow the target PID and record syscalls, printing a summary:
strace -cp PID
# Slow the target PID and print open() syscalls only:
strace -eopen -p PID
# Slow the target PID and print open() and stat() syscalls only:
strace -eopen,stat -p PID
# Slow the target PID and print connect() and accept() syscalls only:
strace -econnect,accept -p PID
# Slow the target command and see what other programs it launches (slow them too!):
strace -qfeexecve command
# Slow the target PID and print time-since-epoch with (distorted) microsecond resolution:
strace -ttt -p PID
# Slow the target PID and print syscall durations with (distorted) microsecond resolution:
strace -T -p PID

4. 两种运行模式。

4.1 一种是通过它启动要跟踪的进程。

用法很简单,在原本的命令前加上strace即可。比如我们要跟踪 “ls -lh /var/log/messages” 这个命令的执行,可以这样:

strace ls -lh /var/log/messages

4.2 另一种是跟踪已经在运行的进程

在不中断进程执行的情况下,理解它在干嘛。 这种情况,给strace传递个-p pid 选项即可。

比如,有个在运行的some_server服务,第一步,查看pid:

pidof some_server                      
17553

得到其pid 17553然后就可以用strace跟踪其执行:

strace -p 17553

完成跟踪时,按ctrl + C 结束strace即可。

strace有一些选项可以调整其行为,我们这里介绍下其中几个比较常用的,然后通过示例讲解其实际应用效果。

5. strace 问题定位案例

.51 定位进程异常退出

问题:机器上有个叫做run.sh的常驻脚本,运行一分钟后会死掉。需要查出死因。

定位:进程还在运行时,通过ps命令获取其pid, 假设我们得到的pid是24298

strace -o strace.log -tt -p 24298

查看strace.log, 我们在最后2行看到如下内容:

22:47:42.803937 wait4(-1,  <unfinished ...>
22:47:43.228422 +++ killed by SIGKILL +++

这里可以看出,进程是被其他进程用KILL信号杀死的。


实际上,通过分析,我们发现机器上别的服务有个监控脚本,它监控一个也叫做run.sh的进程,当发现run.sh进程数大于2时,就会把它杀死重启。结果导致我们这个run.sh脚本被误杀。


进程被杀退出时,strace会输出killed by SIGX(SIGX代表发送给进程的信号)等,那么,进程自己退出时会输出什么呢?


这里有个叫做test_exit的程序,其代码如下:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
       exit(1);
}

我们strace看下它退出时strace上能看到什么痕迹。

strace -tt -e trace=process -f ./test_exit

说明: -e trace=process 表示只跟踪和进程管理相关的系统调用。

输出:

23:07:24.672849 execve("./test_exit", ["./test_exit"], [/* 35 vars */]) = 0
23:07:24.674665 arch_prctl(ARCH_SET_FS, 0x7f1c0eca7740) = 0
23:07:24.675108 exit_group(1)           = ?
23:07:24.675259 +++ exited with 1 +++

可以看出,进程自己退出时(调用exit函数,或者从main函数返回), 最终调用的是exit_group系统调用, 并且strace会输出exited with X(X为退出码)。


可能有人会疑惑,代码里面明明调用的是exit, 怎么显示为exit_group?


这是因为这里的exit函数不是系统调用,而是glibc库提供的一个函数,exit函数的调用最终会转化为exit_group系统调用,它会退出当前进程的所有线程。实际上,有一个叫做_exit()的系统调用(注意exit前面的下划线), 线程退出时最终会调用它。


相关文章
|
6月前
|
移动开发 Ubuntu 网络协议
Linux(11)Debain 调试EC25-EUX总记录
Linux(11)Debain 调试EC25-EUX总记录
235 0
|
10天前
|
缓存 NoSQL Linux
Linux调试
本文介绍了Linux调试、性能分析和追踪的培训资料,涵盖调试、性能分析和追踪的基础知识及常用工具。
168 6
Linux调试
|
6月前
|
网络协议 算法 Linux
【Linux】深入探索:Linux网络调试、追踪与优化
【Linux】深入探索:Linux网络调试、追踪与优化
|
3月前
|
NoSQL Linux C语言
Linux GDB 调试
Linux GDB 调试
62 10
|
3月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
|
3月前
|
Ubuntu Linux
内核实验(四):Qemu调试Linux内核,实现NFS挂载
本文介绍了在Qemu虚拟机中配置NFS挂载的过程,包括服务端的NFS服务器安装、配置和启动,客户端的DHCP脚本添加和开机脚本修改,以及在Qemu中挂载NFS、测试连通性和解决挂载失败的方法。
189 0
内核实验(四):Qemu调试Linux内核,实现NFS挂载
|
4月前
|
运维 Java Linux
(九)JVM成神路之性能调优、GC调试、各内存区、Linux参数大全及实用小技巧
本章节主要用于补齐之前GC篇章以及JVM运行时数据区的一些JVM参数,更多的作用也可以看作是JVM的参数列表大全。对于开发者而言,能够控制JVM的部分也就只有启动参数了,同时,对于JVM的性能调优而言,JVM的参数也是基础。
103 8
|
3月前
|
运维 关系型数据库 MySQL
在Linux中,如何使用strace进行故障排查?
在Linux中,如何使用strace进行故障排查?
|
4月前
|
Linux C# iOS开发
如何用 WinDbg 调试Linux上的 .NET程序
【7月更文挑战第13天】 1. `dotnet-dump`: Collects process dumps with `dotnet-dump collect -p &lt;process_id&gt;`. 2. `lldb`: Debugs Mono runtime apps on macOS/Linux. 3. **Visual Studio Code**: Remotely debugs .NET via the C# extension. 4. **JetBrains Rider**: Supports remote debugging of .NET on Linux.
|
3月前
|
网络协议 安全 Linux
在Linux中,如何使用Netcat进行网络调试和端口扫描?
在Linux中,如何使用Netcat进行网络调试和端口扫描?