You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

bpftrace脚本中uprobe与uretprobe匹配异常问题求助

解决bpftrace中Tcl函数uprobe/uretprobe关联异常的方案

问题根源

你碰到的重复键、出现未设置探针函数名的问题,主要来自两个原因:

  • 通配符匹配到了库中同名但不同的符号(比如弱符号、重载实现或者版本差异符号)
  • 仅用func作为哈希键,无法区分不同线程或不同调用路径的同一函数调用,导致计数混乱

具体修复步骤

1. 精准锁定目标函数符号

先通过工具确认Tcl_NotifyChannel的准确符号,避免通配符误匹配:

nm -D /usr/lib64/libtcl9.0.so | grep Tcl_NotifyChannel

如果输出多个符号,说明存在同名符号,需要进一步用objdump查看地址:

objdump -d /usr/lib64/libtcl9.0.so | grep -A5 -B5 Tcl_NotifyChannel

2. 修改脚本,用线程ID+函数名做关联键

将原脚本的哈希键改为tid(线程ID)+func,确保同一线程内的函数调用能正确关联进入和退出事件:

# 函数进入时调用深度+1,标记递归
uprobe:/usr/lib64/libtcl9.0.so:Tcl_NotifyChannel {
    @call_depth[tid, func] = @call_depth[tid, func] + 1;
    if (@call_depth[tid, func] > 1) {
        @recursive_calls[func] = count();
    }
}

# 函数退出时调用深度-1,归0后清理键
uretprobe:/usr/lib64/libtcl9.0.so:Tcl_NotifyChannel {
    @call_depth[tid, func] = @call_depth[tid, func] - 1;
    if (@call_depth[tid, func] == 0) {
        delete(@call_depth[tid, func]);
    }
}

# 脚本结束时打印结果
END {
    printf("递归调用统计:\n");
    print(@recursive_calls);
    printf("当前调用深度:\n");
    print(@call_depth);
}

3. 若仍有问题,用调用栈做唯一标识

如果线程ID+函数名还是无法区分(比如同一线程内同一函数的嵌套调用路径不同),可以改用callstack作为键的一部分:

uprobe:/usr/lib64/libtcl9.0.so:Tcl_NotifyChannel {
    @call_depth[tid, callstack]++;
    if (@call_depth[tid, callstack] > 1) {
        @recursive_calls[func, callstack] = count();
    }
}

uretprobe:/usr/lib64/libtcl9.0.so:Tcl_NotifyChannel {
    @call_depth[tid, callstack]--;
    if (@call_depth[tid, callstack] == 0) {
        delete(@call_depth[tid, callstack]);
    }
}

4. 验证探针挂载正确性

运行前先检查探针是否只挂载到了目标函数:

bpftrace -l 'uprobe:/usr/lib64/libtcl9.0.so:Tcl_NotifyChannel'

如果输出多个探针,说明还是匹配到了多个符号,此时需要用符号地址来指定:

uprobe:/usr/lib64/libtcl9.0.so:0x<函数地址> {
    # 逻辑同上
}

uretprobe:/usr/lib64/libtcl9.0.so:0x<函数地址> {
    # 逻辑同上
}

内容的提问来源于stack exchange,提问作者Schelte Bron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 11:45:00