根据偏移追溯进程和函数
完整的、生产可用的文档,把 perf 抓到的 libz.so 偏移地址 (0x33e0, 0x33e6, …) 如何追溯到具体进程和函数 的全过程,不能零散。下面我整理一份从头到尾的 全流程排查文档,你拿到后可以直接用。
Linux 系统中 perf 偏移地址溯源完整文档
(以 libz.so.1.2.11 的 0x33e0 等偏移为例)
1️⃣ 确认热点库来源
当 perf top / perf record 输出中出现如下内容:
12.34% 0x33e0 [libz.so.1.2.11]
5.67% 0x33e6 [libz.so.1.2.11]
2.12% 0x33ef [libz.so.1.2.11]
说明 CPU 消耗发生在 libz.so 内部某些函数,但只显示了偏移地址。
2️⃣ 确认是哪个进程调用了 libz.so
方法 A:实时查看(推荐)
perf top -a --show-processes --dsos=libz.so.1.2.11
输出示例:
10.12% nginx(23456) libz.so.1.2.11 [.] deflate_slow
7.89% myapp(12345) libz.so.1.2.11 [.] longest_match
这里能直接看到 进程名 + PID + 库函数名。
方法 B:批量采样
perf record -a -g -- sleep 10
perf report --dsos=libz.so.1.2.11
这样可在报告中查看,哪个进程、哪个函数最耗 CPU。
方法 C:快速确认谁加载了 libz.so
lsof /lib64/libz.so.1.2.11
只知道 哪些进程加载了库,无法判断 CPU 热点。
3️⃣ 确定 libz.so 加载基址
对热点进程,查询其内存映射:
cat /proc/<PID>/maps | grep libz.so
示例输出:
7f3b9c7a0000-7f3b9c7bc000 r-xp 00000000 fd:00 123456 /lib64/libz.so.1.2.11
基址是 0x7f3b9c7a0000,偏移量是 0x00000000,所以 0x33e0 就是真实地址:
真实地址 = 基址 + 偏移
= 0x7f3b9c7a0000 + 0x33e0
4️⃣ 将偏移地址解析为函数
方法 A:使用 addr2line
addr2line -e /lib64/libz.so.1.2.11 0x33e0
如果库带调试符号,会输出:
deflate.c:124
方法 B:使用 objdump
objdump -d /lib64/libz.so.1.2.11 --start-address=0x33e0 --stop-address=0x3400
可以看到汇编代码和函数标签,确认偏移属于哪个函数。
方法 C:快速查符号表
nm -D /lib64/libz.so.1.2.11 | grep 33e0
objdump -T /lib64/libz.so.1.2.11 | grep 33e0
如果符号导出表有对应函数,会直接显示。
5️⃣ 脚本化自动解析(可直接用)
编写一个脚本 resolve_libz_addr.sh:
#!/bin/bash
PID=$1
OFFSET=$2
LIB=/lib64/libz.so.1.2.11
BASE=$(cat /proc/$PID/maps | grep libz.so | head -1 | awk '{print $1}' | cut -d- -f1)
BASE_DEC=$((16#$BASE))
OFFSET_DEC=$((16#$OFFSET))
ADDR=$((BASE_DEC + OFFSET_DEC))
printf "进程 PID: %s\n库基址: %s\n偏移: %s\n实际地址: 0x%x\n\n" $PID $BASE $OFFSET $ADDR
addr2line -e $LIB $OFFSET
用法示例:
./resolve_libz_addr.sh 12345 33e0
6️⃣ 结论
-
确认进程是谁 →
perf top -a --show-processes -
确认偏移对应的函数 →
/proc/<pid>/maps + addr2line/objdump -
脚本化 → 一步得到 PID + 函数名
浙公网安备 33010602011771号