callgrind 输出全是地址而无函数名,是因为编译时未加 -g 参数导致缺少 dwarf 调试信息;需用 gcc -g 编译、避免 strip、分析时通过 --exe 或 kcachegrind ./myapp 显式指定可执行文件路径。

Callgrind 输出全是地址,看不到函数名
这是最常见也最容易被忽略的问题:Callgrind 默认不加载调试符号,所以 callgrind_annotate 或 kcachegrind 打开结果时只显示类似 0x40123a 的地址,无法定位到函数或源码行。
编译时没加 -g,Callgrind 就没法反查符号
Callgrind 本身不解析符号,它只记录调用关系和指令计数;真正把地址映射成函数名、文件名、行号的是后续分析工具(如 callgrind_annotate),而它们严重依赖二进制中嵌入的 DWARF 调试信息。
- 必须用
gcc -g或g++ -g编译目标程序(不是 Valgrind 本身) - 如果用了优化(如
-O2),建议加-g -O2—— 大多数现代编译器支持带调试信息的优化构建 - 确认符号未被 strip:运行
file ./myapp,输出应含with debug_info;若显示stripped,说明调试信息已被删掉 - 静态链接(
-static)会增大二进制体积,但不会导致符号丢失;真正危险的是后续执行了strip ./myapp
callgrind_annotate 不显示函数名?检查这几个参数
callgrind_annotate 默认只显示 top N 热点,且对符号解析很“懒”——它不会主动扫描整个二进制,而是按需查找。容易漏掉低频但关键的函数。
- 强制显示所有函数:加
--auto=yes参数,让工具自动尝试解析所有已知地址 - 指定可执行文件路径:用
--exe=./myapp显式告诉它去哪里找符号(尤其当你用valgrind --tool=callgrind --dump-instr=yes生成了指令级数据时) - 避免误读共享库:默认会统计 libc 等系统库调用;加
--inclusive=no可聚焦你自己的代码 - 验证是否真能解析:先跑
addr2line -e ./myapp 0x40123a,如果返回空或问号,说明符号确实缺失
用 kcachegrind 打开 callgrind.out.* 仍无函数名?别跳过这步
kcachegrind 图形界面更友好,但它同样依赖符号表。很多人装完就双击打开,却忘了它需要知道主程序路径。
- 启动时用
kcachegrind ./myapp callgrind.out.12345,把可执行文件路径作为第一个参数传入 - 或者打开后点击菜单 Settings → Configure KCacheGrind → Executable,手动填入
./myapp - 如果程序是通过
LD_PRELOAD加载了自定义 so,且该 so 也没带-g,那对应部分永远显示为???—— 这不是 bug,是符号确实不存在 - 注意:
kcachegrind不支持直接读取压缩的.out.gz,得先gunzip解压
真正卡住人的地方往往不是 Callgrind 本身,而是符号链断在了编译、链接或分析任一环节。只要确保 gcc -g 编译、不 strip、分析时显式指定可执行路径,95% 的“无符号名”问题就消失了。











