Linux 调试与追踪工具
Linux 系统调试与追踪工具集——strace、traceroute、ltrace 的使用方法与输出解读。
📖 traceroute:网络路径追踪
日常说的 trace,在 Linux 里一般指四类工具:
1)traceroute(网络路由跟踪)
2)strace(用户态进程系统调用跟踪)
3)ltrace(用户态库函数跟踪)
4)ftrace(内核态函数/事件跟踪)
下面按场景逐个详解。
🌐 网络路径追踪 traceroute
作用
探测从本机到目标 IP/域名沿途经过的路由节点 & 延迟,定位网络丢包/卡顿点。
原理
利用 IP 头 TTL(生存时间):
- TTL=1 → 第一跳路由超时返回 ICMP → 拿到第1跳 IP
- TTL=2 → 第二跳超时 → 拿到第2跳 IP
- ……直到到达目标
常用参数
traceroute [选项] 目标IP/域名
-d:不解析域名(更快)-f TTL:起始 TTL(默认1)-m MAX_TTL:最大跳数(默认30)-p PORT:指定目的端口(默认33434)-q N:每跳发 N 个包(默认3)-T:用 TCP 替代 UDP(穿透防火墙)
示例
traceroute -d www.baidu.com
输出:
1 192.168.1.1 0.5ms 0.4ms 0.4ms
2 10.10.8.1 5.2ms 5.1ms 5.1ms
3 * * * (防火墙无响应)
4 203.0.113.45 12.4ms 12.4ms 12.3ms
*:该跳无响应(防火墙拦截)- 延迟突增:链路拥塞
Windows 对应命令
tracert 目标IP
🔌 ⚡ strace:跟踪进程的系统调用(排障神器)
作用
监控进程执行的所有系统调用(open/read/write/socket/connect 等)及返回值,定位:
- 程序启动失败(缺文件、权限不足)
- 进程卡死(卡在某个 syscall)
- 性能慢(频繁 syscall、IO 阻塞)
安装
## 📌 Debian/Ubuntu
apt install strace
## 📌 CentOS/RHEL
yum install strace
常用用法
1)跟踪新进程
strace ls
输出:
execve("/bin/ls", ["ls"], 0x7ffd4d2e2000) = 0
brk(NULL) = 0x55f87a2c7000
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
...
2)跟踪已运行进程(-p PID)
strace -p 1234
3)输出到文件(-o)
strace -o trace.log -p 1234
4)过滤特定系统调用(-e trace=)
## 💾 只看文件相关调用
strace -e trace=open,read,close cat /etc/passwd
## 🌐 只看网络调用
strace -e trace=network curl www.baidu.com
5)跟踪子进程(-f)
strace -f ./test.sh
6)统计耗时(-c)
strace -c ls
输出各 syscall 调用次数、耗时占比。
关键输出字段
syscall(arg1, arg2...) = 返回值- 返回值
-1:失败,errno显示原因(如ENOENT文件不存在)
🔧 ltrace:跟踪库函数调用
作用
跟踪进程调用的动态库函数(如 malloc/free/printf/strcpy),补 strace 看不到的用户态库调用。
安装
apt install ltrace
yum install ltrace
常用用法
## 📌 跟踪 ls 的库函数
ltrace ls
## 📌 统计调用次数
ltrace -c ls
## 🔌 同时显示系统调用
ltrace -S ls
## 📌 过滤特定函数
ltrace -e "*strcpy*" cp a.txt b.txt
📌 ⚙️ ftrace:Linux 内核级跟踪(高级)
作用
跟踪内核函数、调度、中断、系统事件,定位内核态性能问题、死锁、调度异常。
前提:挂载 debugfs
mount -t debugfs none /sys/kernel/debug
cd /sys/kernel/debug/tracing
核心文件
current_tracer:当前跟踪器(function/function_graph 等)tracing_on:1=开始跟踪,0=停止set_ftrace_filter:过滤要跟踪的内核函数trace:跟踪结果输出
常用示例
1)函数调用跟踪(function)
echo function > current_tracer
echo 1 > tracing_on
## 📊 执行要监控的操作(如 ls)
echo 0 > tracing_on
cat trace
2)函数调用图(function_graph,带耗时)
echo function_graph > current_tracer
echo __do_fault > set_graph_function # 只跟踪缺页异常
echo 1 > tracing_on
## 📌 执行操作
echo 0 > tracing_on
cat trace
3)跟踪系统调用
echo syscalls > current_tracer
输出解读
TASK-PID CPU#:进程名-PID/CPUTIMESTAMP:时间戳FUNCTION:内核函数DURATION:函数耗时(function_graph 模式)
🚀 四种 trace 工具对比(选型)
- traceroute:网络路由、延迟、丢包 → 网络连通性排障
- strace:进程系统调用(文件/网络/IO)→ 应用启动失败、卡死、权限问题
- ltrace:用户态库函数(malloc/printf)→ 内存泄漏、库调用异常
- ftrace:内核函数/调度/中断 → 内核性能、死锁、调度问题
🌐 实战场景推荐
- 访问文件报错:
strace -e trace=open,stat 程序 - 接口超时/连不上:
traceroute 目标IP+strace -e trace=network 程序 - 进程 CPU 高:
strace -c看高频 syscall;或ftrace看内核热点 - 程序崩溃:
strace看崩溃前最后调用;ltrace看库调用;dmesg看内核 OOM/Oops
🔍 strace 输出详解
📖 strace 输出字段 & 含义(重点)
📖 1. 基础通用输出格式
系统调用名(参数1, 参数2, ...) = 返回值 【错误信息】
1.1 逐段拆解示例
执行 strace ls,截取典型行:
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
read(3, "drwxr-xr-x 2 root root 4096 Jun 9 10:00 dir\n", 8192) = 128
futex(0x7f8b2c0009d8, FUTEX_WAIT, 2, NULL) = -1 EAGAIN (资源暂时不可用)
-
openat:系统调用名称,代表当前内核操作 -
(AT_FDCWD, ".", ...):调用入参,路径、权限、标志位等 -
= 3:返回值 -
正数:成功,一般是文件描述符 fd
-
0:执行成功(无返回数据) -
-1:调用失败 -
EAGAIN:错误码,括号内是文字描述
🔌 1.2 高频系统调用 + 字段解读
(1)文件类调用 open / openat / read / write / close
openat 示例
openat(AT_FDCWD, "/etc/hosts", O_RDONLY) = 4
AT_FDCWD:基于当前工作目录查找文件"/etc/hosts":目标文件路径O_RDONLY:只读模式;常见标识:O_WRONLY(只写)、O_RDWR(读写)、O_CREAT(创建文件)= 4:成功,返回文件描述符 fd=4
read / write 示例
read(4, "127.0.0.1 localhost\n", 8192) = 20
write(1, "hello\n", 6) = 6
- 第1个参数:文件描述符(
1标准输出 stdout,2标准错误 stderr) - 第2个参数:读取/写入的内容
- 第3个参数:期望读写字节数
- 末尾数字:实际读写字节数
close 示例
close(4) = 0
参数=文件描述符,=0 表示关闭成功。
(2)网络类调用 socket / connect / accept / send / recv
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("1.1.1.1")}, 16) = 0
AF_INET:IPv4 协议;SOCK_STREAM:TCP 套接字=5:创建socket成功,fd=5connect参数:IP+端口结构体,=0连接成功- 失败示例:
connect(...) = -1 ECONNREFUSED (连接被拒绝)
(3)进程/线程类 fork / clone / execve
execve("/bin/ls", ["ls"], [/* 25 vars */]) = 0
clone(child_stack=NULL, flags=CLONE_THREAD) = 12345
execve:加载可执行程序,第一个参数为程序路径clone:Linux 创建线程/进程的底层调用,返回子进程/线程PID
(4)锁/等待类 futex / poll / select(进程卡死高频)
futex 线程锁
futex(0x7fxxxx, FUTEX_WAIT, 1, NULL) = ?
- 作用:Linux 线程互斥锁、条件等待
- 现象:该行一直卡住不动 → 线程死锁/锁竞争,进程假死
poll / select IO 多路复用
poll([{fd=3, events=POLLIN}], 1, -1)
fd=3:监听的文件描述符POLLIN:等待读事件- 最后
-1:无限阻塞等待(无事件则一直卡在这里)
⚙️ ⚙️ 1.3 带时间戳/耗时参数的输出解读
1)-t 显示系统时间
10:20:30 openat(...) = 3
开头 10:20:30:系统当前时间,定位异常发生时刻。
2)-T 显示单次调用耗时(重点排查慢调用)
read(3, "xxx", 8192) = 128 <0.000123>
poll(...) = 1 <5.234567>
<0.000123>:本次系统调用耗时,单位 秒- 耗时秒级以上:典型慢调用、IO/网络阻塞
3)-c 统计汇总输出(strace -c PID)
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
80.00 0.500000 100 5000 read
15.00 0.093750 15 625 10 write
5.00 0.031250 31 1 poll
------ ----------- ----------- --------- --------- total
字段说明:
% time:该系统调用耗时占总耗时百分比(占比高=性能瓶颈)seconds:累计总耗时(秒)usecs/call:单次调用平均耗时(微秒)calls:总调用次数(次数暴增=频繁系统调用,CPU高)errors:失败次数syscall:系统调用名
📌 1.4 高频错误码含义(排障核心)
| 错误码 | 英文描述 | 中文含义 | 典型场景 |
| ENOENT | No such file or directory | 文件/路径不存在 | 程序缺配置、路径写错 |
| EACCES | Permission denied | 权限不足 | 读写文件、绑定特权端口 |
| EEXIST | File exists | 文件已存在 | 重复创建文件/目录 |
| EAGAIN | Resource temporarily unavailable | 资源暂时不可用 | 非阻塞IO无数据、锁争抢 |
| ECONNREFUSED | Connection refused | 连接被拒绝 | 端口未监听、服务未启动 |
| ETIMEDOUT | Connection timed out | 连接超时 | 网络不通、防火墙拦截 |
| EINTR | Interrupted system call | 调用被信号中断 | 进程收到 kill 信号 |
| ENOMEM | Out of memory | 内存不足 | 内存耗尽、OOM 前兆 |
📌 ⚡ ftrace 输出字段 & 含义(内核跟踪)
前置:进入目录 cd /sys/kernel/debug/tracing,所有结果通过 cat trace 查看。
🔄 2.1 公共头部字段(所有跟踪模式通用)
## 📌 tracer: function
#
## 📌 TASK-PID CPU# TIMESTAMP FUNCTION
## 📌 进程名-PID CPU编号 时间戳 内核函数名
TASK-PID:进程名 + 进程IDCPU#:当前运行在第几颗CPU核心TIMESTAMP:时间戳(单位:秒,从系统启动开始计时)FUNCTION:内核函数名称
🔄 2.2 模式1:function 纯函数跟踪
示例输出
bash-1234 [001] 1234.567890: kswapd0 <- schedule
逐字段:
bash-1234:进程名=bash,PID=1234[001]:运行在 CPU11234.567890:系统启动后经过的秒数kswapd0:当前执行的内核函数(内存回收线程)<- schedule:调用方函数(由 schedule 调度函数触发)
典型场景:
- 大量
kswapd:内存紧张,内核频繁回收内存、使用 Swap - 大量
softirq函数:软中断繁忙(网络/IO 压力大)
🔄 2.3 模式2:function_graph 函数调用图(带耗时、层级,最常用)
示例输出
1) nginx-5678 [000] 2345.123456: | __do_fault() {
2) nginx-5678 [000] 2345.123460: | alloc_page() {
3) nginx-5678 [000] 2345.123462: 2.000 us | }
4) nginx-5678 [000] 2345.123465: 9.000 us | }
字段&符号解读:
- 行首数字
1):CPU 编号 nginx-5678:进程+PID- 缩进:函数调用层级(大函数内部调用子函数)
{:函数开始执行}:函数执行结束2.000 us:函数执行耗时(微秒)
排障要点:
- 单函数耗时几百微秒/毫秒:内核态慢函数,系统卡顿根源
- 嵌套层级极深:内核调用链复杂,调度压力大
🔌 2.4 模式3:syscalls 系统调用跟踪(内核视角)
示例
ls-9012 [002] 3456.789000: sys_openat(filename="/etc/passwd")
ls-9012 [002] 3456.789010: sys_openat -> 3
sys_openat:内核层系统调用入口(对应应用层openat)filename=xxx:调用参数-> 3:返回文件描述符 fd=3
🔧 ltrace 输出字段 & 含义(库函数跟踪)
📖 3.1 基础格式
库函数名(参数1, 参数2...) = 返回值
示例 1:普通库调用
ls->strlen("test") = 4
ls->malloc(1024) = 0x7f1234567890
ls:当前进程名strlen/malloc:C 标准库函数- 括号内:入参
= 4/=0x...返回值(字符串长度 / 内存地址)
示例 2:ltrace -c 统计输出
% time seconds usecs/call calls function
------ ----------- ----------- --------- ---------
70.00 0.200000 20 1000 strlen
30.00 0.080000 40 200 malloc
字段和 strace -c 完全一致:耗时占比、总耗时、单次耗时、调用次数、函数名。
典型故障
- 大量
malloc/free调用:频繁内存分配释放,疑似内存泄漏 - 函数返回
NULL:库调用失败
🌐 ⚙️ traceroute 输出字段 & 含义(网络路由)
📖 4.1 基础输出示例
1 192.168.1.1 (192.168.1.1) 0.321 ms 0.289 ms 0.276 ms
2 10.0.0.1 5.123 ms 5.098 ms 5.101 ms
3 * * *
4 220.181.xxx.xxx 12.345 ms 12.333 ms 12.321 ms
逐列解读:
- 第一列(数字):路由跳数(第1跳、第2跳…)
- 第二部分:路由节点域名/IP
- 后三列:三次探测的延迟(毫秒 ms)
📌 4.2 特殊符号解读
* * *:该路由节点无响应
- 原因:防火墙拦截 ICMP/TCP 探测包、路由节点禁回包
- 延迟突然大幅飙升:当前节点链路拥塞、带宽瓶颈
- 跳数过多 + 持续丢包:链路不稳定
⚙️ ⚙️ 4.3 补充参数输出
- 使用
-d:不解析域名,只显示IP,输出更简洁 - 使用
-T:基于TCP探测,适合UDP被防火墙拦截的场景
🚀 综合排障速查(现象 + 工具输出特征 + 结论)
- 程序启动失败strace 出现
open(...) = -1 ENOENT→ 缺失文件/配置
strace 出现open(...) = -1 EACCES→ 权限不足 - 进程卡死、假死strace 卡在
futex→ 线程死锁
strace 卡在poll/select→ IO/网络等待
ftrace 某内核函数耗时极高 → 内核态阻塞 - CPU 占用高strace
-c某系统调用calls上万次 → 频繁用户态系统调用
ftrace 大量软中断函数 → 网络/硬件中断风暴 - 网络连不上strace
connect = -1 ECONNREFUSED→ 服务未监听
traceroute 中间跳* * *→ 链路/防火墙拦截 - 内存异常ftrace 大量
kswapd函数 → 内存不足、Swap 频繁使用
关联文档
- Linux 内核学习 — 内核基础
- 用户态与内核态 — 用户态/内核态