根据偏移追溯进程和函数

完整的、生产可用的文档,把 perf 抓到的 libz.so 偏移地址 (0x33e0, 0x33e6, …) 如何追溯到具体进程和函数 的全过程,不能零散。下面我整理一份从头到尾的 全流程排查文档,你拿到后可以直接用。


Linux 系统中 perf 偏移地址溯源完整文档

(以 libz.so.1.2.110x33e0 等偏移为例)


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️⃣ 结论

  1. 确认进程是谁perf top -a --show-processes

  2. 确认偏移对应的函数/proc/<pid>/maps + addr2line/objdump

  3. 脚本化 → 一步得到 PID + 函数名

posted on 2025-08-18 17:09  吃草的青蛙  阅读(12)  评论(0)    收藏  举报

导航