Linux

Linux 调试与追踪工具

·21 分钟阅读·8335 字

strace、traceroute、ltrace、perf 等 Linux 调试追踪工具的用法与输出解读

📋 目录

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/CPU
  • TIMESTAMP:时间戳
  • FUNCTION:内核函数
  • DURATION:函数耗时(function_graph 模式)

🚀 四种 trace 工具对比(选型)

  • traceroute:网络路由、延迟、丢包 → 网络连通性排障
  • strace:进程系统调用(文件/网络/IO)→ 应用启动失败、卡死、权限问题
  • ltrace:用户态库函数(malloc/printf)→ 内存泄漏、库调用异常
  • ftrace:内核函数/调度/中断 → 内核性能、死锁、调度问题

🌐 实战场景推荐

  1. 访问文件报错strace -e trace=open,stat 程序
  2. 接口超时/连不上traceroute 目标IP + strace -e trace=network 程序
  3. 进程 CPU 高strace -c 看高频 syscall;或 ftrace 看内核热点
  4. 程序崩溃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=5
  • connect 参数: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

字段说明:

  1. % time:该系统调用耗时占总耗时百分比(占比高=性能瓶颈)
  2. seconds:累计总耗时(秒)
  3. usecs/call:单次调用平均耗时(微秒)
  4. calls:总调用次数(次数暴增=频繁系统调用,CPU高)
  5. errors:失败次数
  6. syscall:系统调用名

📌 1.4 高频错误码含义(排障核心)

错误码英文描述中文含义典型场景
ENOENTNo such file or directory文件/路径不存在程序缺配置、路径写错
EACCESPermission denied权限不足读写文件、绑定特权端口
EEXISTFile exists文件已存在重复创建文件/目录
EAGAINResource temporarily unavailable资源暂时不可用非阻塞IO无数据、锁争抢
ECONNREFUSEDConnection refused连接被拒绝端口未监听、服务未启动
ETIMEDOUTConnection timed out连接超时网络不通、防火墙拦截
EINTRInterrupted system call调用被信号中断进程收到 kill 信号
ENOMEMOut of memory内存不足内存耗尽、OOM 前兆

📌 ⚡ ftrace 输出字段 & 含义(内核跟踪)

前置:进入目录 cd /sys/kernel/debug/tracing,所有结果通过 cat trace 查看。

🔄 2.1 公共头部字段(所有跟踪模式通用)

## 📌 tracer: function
#
## 📌 TASK-PID   CPU#      TIMESTAMP  FUNCTION
## 📌 进程名-PID  CPU编号   时间戳    内核函数名
  • TASK-PID:进程名 + 进程ID
  • CPU#:当前运行在第几颗CPU核心
  • TIMESTAMP:时间戳(单位:秒,从系统启动开始计时)
  • FUNCTION:内核函数名称

🔄 2.2 模式1:function 纯函数跟踪

示例输出

bash-1234  [001]  1234.567890: kswapd0 <- schedule

逐字段:

  1. bash-1234:进程名=bash,PID=1234
  2. [001]:运行在 CPU1
  3. 1234.567890:系统启动后经过的秒数
  4. kswapd0当前执行的内核函数(内存回收线程)
  5. <- 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. 行首数字 1):CPU 编号
  2. nginx-5678:进程+PID
  3. 缩进:函数调用层级(大函数内部调用子函数)
  4. {:函数开始执行
  5. }:函数执行结束
  6. 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. 第一列(数字):路由跳数(第1跳、第2跳…)
  2. 第二部分:路由节点域名/IP
  3. 后三列:三次探测的延迟(毫秒 ms)

📌 4.2 特殊符号解读

  1. * * *:该路由节点无响应
  • 原因:防火墙拦截 ICMP/TCP 探测包、路由节点禁回包
  1. 延迟突然大幅飙升:当前节点链路拥塞、带宽瓶颈
  2. 跳数过多 + 持续丢包:链路不稳定

⚙️ ⚙️ 4.3 补充参数输出

  • 使用 -d:不解析域名,只显示IP,输出更简洁
  • 使用 -T:基于TCP探测,适合UDP被防火墙拦截的场景

🚀 综合排障速查(现象 + 工具输出特征 + 结论)

  1. 程序启动失败strace 出现 open(...) = -1 ENOENT → 缺失文件/配置
    strace 出现 open(...) = -1 EACCES → 权限不足
  2. 进程卡死、假死strace 卡在 futex → 线程死锁
    strace 卡在 poll/select → IO/网络等待
    ftrace 某内核函数耗时极高 → 内核态阻塞
  3. CPU 占用高strace -c 某系统调用 calls 上万次 → 频繁用户态系统调用
    ftrace 大量软中断函数 → 网络/硬件中断风暴
  4. 网络连不上strace connect = -1 ECONNREFUSED → 服务未监听
    traceroute 中间跳 * * * → 链路/防火墙拦截
  5. 内存异常ftrace 大量 kswapd 函数 → 内存不足、Swap 频繁使用

关联文档