AttributeError: /lib/x86_64-linux-gnu/libbcc.so.0: undefined symbol: bpf_module_create_b

文章描述了在Ubuntu22的虚拟机中,安装bcc工具后尝试运行python3版本的execsnoop时遇到的AttributeError,原因是libbcc.so.0库缺少bpf_module_create_b符号。作者通过检查python版本、libbcc库和python3的bcc库,发现是bcc库版本不匹配导致的问题。解决方案是将新编译的bcc库中的python3bcc模块复制到python3的库中,从而解决了问题。

AttributeError: /lib/x86_64-linux-gnu/libbcc.so.0: undefined symbol: bpf_module_create_b

背景

在Ubuntu22的虚拟机中,使用源码编译并安装好bcc工具库后,执行bcc工具python3 /usr/share/bcc/tools/execsnoop报错。

报错信息

报错信息如下:

root@ubuntu2204vm:/usr/share/bcc/tools# ./execsnoop
Traceback (most recent call last):
  File "/usr/share/bcc/tools/./execsnoop", line 23, in <module>
    from bcc import BPF
  File "/usr/lib/python3/dist-packages/bcc/__init__.py", line 27, in <module>
    from .libbcc import lib, bcc_symbol, bcc_symbol_option, bcc_stacktrace_build_id, _SYM_CB_TYPE
  File "/usr/lib/python3/dist-packages/bcc/libbcc.py", line 20, in <module>
    lib.bpf_module_create_b.restype = ct.c_void_p
    ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ctypes/__init__.py", line 389, in __getattr__
    func = self.__getitem__(name)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ctypes/__init__.py", line 394, in __getitem__
    func = self._FuncPtr((name_or_ordinal, self))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: /lib/x86_64-linux-gnu/libbcc.so.0: undefined symbol: bpf_module_create_b

解决方法

网上的目前的解决办法

主要还是python版本问题,将python2切换为python3。而我这边显然不是这个问题,因为我的机子上只有python3

复制已编译的bcc库中的python bcc库到python3的库中

cp -r /root/ebpf/bcc/build/src/python/bcc-python3/bcc/* /usr/lib/python3/dist-packages/bcc/

错误分析过程

报错的相关路径

根据报错信息,和报错相关的路径:
/lib/x86_64-linux-gnu/libbcc.so.0: bcc库采用的libbcc.so.0
/usr/lib/python3/dist-packages/bcc: 报错的bcc库

python版本检测

使用的均为python3,没有python2,所以不存在版本问题

# update-alternatives --config python
There are 2 choices for the alternative python (providing /usr/bin/python).

  Selection    Path                 Priority   Status
------------------------------------------------------------
* 0            /usr/bin/python3.11   2         auto mode
  1            /usr/bin/python3.10   1         manual mode
  2            /usr/bin/python3.11   2         manual mode

libbcc库检查

# ls -lh /lib/x86_64-linux-gnu/ |grep libbcc
-rw-r--r--  1 root root  5.0M May  1 19:34 libbcc.a
-rw-r--r--  1 root root  1.5M May  1 19:33 libbcc_bpf.a
lrwxrwxrwx  1 root root    15 Jan 18  2021 libbcc_bpf.so -> libbcc_bpf.so.0
lrwxrwxrwx  1 root root    20 May  1 19:35 libbcc_bpf.so.0 -> libbcc_bpf.so.0.27.0
-rw-r--r--  1 root root   51K Jan 18  2021 libbcc_bpf.so.0.18.0
-rw-r--r--  1 root root  2.8M May  1 19:33 libbcc_bpf.so.0.27.0
-rw-r--r--  1 root root  243K May  1 19:33 libbcc-loader-static.a
lrwxrwxrwx  1 root root    11 Jan 18  2021 libbcc.so -> libbcc.so.0
lrwxrwxrwx  1 root root    16 May  1 19:35 libbcc.so.0 -> libbcc.so.0.27.0
-rw-r--r--  1 root root  3.3M Jan 18  2021 libbcc.so.0.18.0
-rw-r--r--  1 root root  105M May  1 19:34 libbcc.so.0.27.0

可以看到libbcc库的实际指向为:
libbcc.so.0 -> libbcc.so.0.27.0

根据报错内容,python库需要bpf_module_create_b,而libbcc.so.0.27.0中没有
可以通过以下命令查看:

# strings /lib/x86_64-linux-gnu/libbcc.so.0.27.0 |grep bpf_module_create_
bpf_module_create_c
bpf_module_create_c_from_string
bpf_module_create_c.cold
bpf_module_create_c_from_string.cold
bpf_module_create_c
bpf_module_create_c_from_string

此时注意到上一个步骤中的libbcc.so.0.18.0,同样进行bpf_module_create_b检查

# strings /lib/x86_64-linux-gnu/libbcc.so.0.18.0 |grep bpf_module_create_
bpf_module_create_b
bpf_module_create_c
bpf_module_create_c_from_string

发现存在bpf_module_create_b,即便不进行时间对比,通过版本号0.18.0与0.27.0也知道,
python3的bcc库竟然请求的是老版(0.18.0)的bcc lib库

python3 bcc库检查

# ll  /usr/lib/python3/dist-packages/bcc/
total 212
drwxr-xr-x   3 root root  4096 May  2 00:13 ./
drwxr-xr-x 156 root root 12288 May  1 19:36 ../
-rw-r--r--   1 root root  2566 Jan 18  2021 containers.py
-rw-r--r--   1 root root 20914 Jan 18  2021 disassembler.py
-rw-r--r--   1 root root 58581 Jan 18  2021 __init__.py
-rw-r--r--   1 root root 12951 Jan 18  2021 libbcc.py
-rw-r--r--   1 root root  4693 Jan 18  2021 perf.py
drwxr-xr-x   2 root root  4096 May  1 19:37 __pycache__/
-rw-r--r--   1 root root  9656 Jan 18  2021 syscall.py
-rw-r--r--   1 root root 40588 Jan 18  2021 table.py
-rw-r--r--   1 root root  1604 Jan 18  2021 tcp.py
-rw-r--r--   1 root root  9102 Jan 18  2021 usdt.py
-rw-r--r--   1 root root  4904 Jan 18  2021 utils.py
-rw-r--r--   1 root root    23 Jan 18  2021 version.py

根据文件时间可以确定,确实都是21年的老库,遂进行替换,先查找bcc源码中的bcc python库:

# find / -name libbcc.py -ls 2>/dev/null
  2360806  16 ... 12951 Jan 18  2021 /usr/lib/python3/dist-packages/bcc/libbcc.py
  1054215  16 ... 14561 May  1 19:32 /root/ebpf/bcc/build/src/python/bcc-python3/build/lib/bcc/libbcc.py
  1053905  16 ... 14561 May  1 19:32 /root/ebpf/bcc/build/src/python/bcc-python3/bcc/libbcc.py
  1052874  16 ... 14561 May  1 19:31 /root/ebpf/bcc/src/python/bcc/libbcc.py 

因为笔者对python并不算熟悉,不知道如何进行正确替换,所以直接进行的复制
cp -r /root/ebpf/bcc/build/src/python/bcc-python3/bcc/* /usr/lib/python3/dist-packages/bcc/

替换后再次执行bcc命令,问题成功得到解决,效果如下:

# ./execsnoop
PCOMM            PID     PPID    RET ARGS
sshd             7924    909       0 /usr/sbin/sshd -D -R
00-header        7928    7927      0 /etc/update-motd.d/00-header
uname            7929    7928      0 /usr/bin/uname -o
uname            7930    7928      0 /usr/bin/uname -r
uname            7931    7928      0 /usr/bin/uname -m
你已经找到了系统中多个路径下的 OpenSSL 静态库文件: ``` /usr/local/arm-openssl/lib/libssl.a /usr/local/arm-openssl/lib/libcrypto.a /usr/lib/x86_64-linux-gnu/libssl.a /usr/lib/x86_64-linux-gnu/libcrypto.a ``` 这说明你的系统中 **同时存在两套 OpenSSL 静态库**: | 路径 | 架构 | 用途 | |------|------|------| | `/usr/local/arm-openssl/...` | ARM(交叉编译) | 用于嵌入式设备、Android、ARM Linux 等目标平台 | | `/usr/lib/x86_64-linux-gnu/...` | x86_64(本地 PC) | 用于在当前 Ubuntu 主机上编译和链接程序 | --- ## ✅ 详细分析每个文件的含义 ### 1. `/usr/local/arm-openssl/lib/libcrypto.a` - **功能**:OpenSSL 核心加密算法库(如 AES、SHA256、RSA、ECDSA) - **架构**:为 **ARM 平台** 编译(可能是通过交叉编译器生成) - **使用场景**:打包进 ARM 设备固件或 Android NDK 项目 ### 2. `/usr/local/arm-openssl/lib/libssl.a` - **功能**:TLS/SSL 协议实现(依赖 `libcrypto.a`) - **架构**:ARM - **注意**:如果你只做加解密,不一定需要它;但要做 HTTPS 或 TLS 通信就必须用 ### 3. `/usr/lib/x86_64-linux-gnu/libcrypto.a` - **功能**:同上,核心加密库 - **架构**:x86_64(你的 Ubuntu 桌面环境原生架构) - **用途**:在本机编译 C/C++ 程序时静态链接 OpenSSL 加密功能 ### 4. `/usr/lib/x86_64-linux-gnu/libssl.a` - **功能**:TLS 协议层 - **架构**:x86_64 - **用途**:开发基于 TLS 的服务器/客户端(如自制 HTTPS 工具) --- ## 🔍 如何确认这些 `.a` 文件是给哪个 CPU 架构的? 使用 `file` 和 `objdump` 命令查看目标架构。 ### 示例:检查 `/usr/lib/x86_64-linux-gnu/libcrypto.a` ```bash file /usr/lib/x86_64-linux-gnu/libcrypto.a ``` 输出: ``` /usr/lib/x86_64-linux-gnu/libcrypto.a: current ar archive ``` 再看其中一个成员的目标架构(提取一个 `.o` 文件并检查): ```bash objdump -f /usr/lib/x86_64-linux-gnu/libcrypto.a | grep architecture ``` 你会看到类似: ``` architecture: i386:x86-64, flags 0x00000011: ``` ✅ 表示这是 **x86_64 架构** --- ### 检查 ARM 版本是否真的是 ARM ```bash objdump -f /usr/local/arm-openssl/lib/libcrypto.a | grep architecture ``` 预期输出: ``` architecture: arm, flags 0x00000011: ``` 或者你可以运行: ```bash readelf -A /usr/local/arm-openssl/lib/libcrypto.a ``` 如果提示 “Attribute Section: aeabi”,那就是典型的 ARM EABI 格式。 --- ## 🧩 使用建议:如何选择正确的 `.a` 文件? | 你要做什么 | 应该使用的库 | |----------|-------------| | 在 PC 上测试加解密代码 | `/usr/lib/x86_64-linux-gnu/libcrypto.a` | | 编译运行在树莓派上的程序 | 同上(如果是树莓派 3+/4,也是 aarch64) | | 交叉编译给 ARM 嵌入式板卡 | `/usr/local/arm-openssl/lib/lib{crypto,ssl}.a` | | 打包 SDK 提供给客户 | 推荐使用自己编译的静态库(避免依赖) | --- ## 💡 编译示例:链接 x86_64libcrypto.a ```c // test_sha256.c #include <openssl/sha.h> #include <stdio.h> int main() { unsigned char data[] = "Hello, World!"; unsigned char hash[32]; SHA256(data, sizeof(data)-1, hash); for (int i = 0; i < 32; i++) { printf("%02x", hash[i]); } printf("\n"); return 0; } ``` ### 编译命令(静态链接): ```bash gcc test_sha256.c \ -I/usr/include/openssl \ /usr/lib/x86_64-linux-gnu/libcrypto.a \ -o test_sha256_static ``` > ⚠️ 注意:必须指定 `-I/usr/include/openssl` 包含头文件路径。 --- ## ❗ 常见问题与注意事项 ### 1. 头文件不匹配 确保 `.a` 库版本与你包含的头文件一致。 比如你用了 `/usr/local/arm-openssl/lib/libcrypto.a`,就应该用: ```c #include <openssl/crypto.h> ``` 并且编译时加: ```bash -I/usr/local/arm-openssl/include ``` 否则可能出现符号错误或结构体大小不一致。 --- ### 2. 链接顺序很重要 静态库链接时遵循 **从高阶到低阶** 的顺序: ```bash gcc main.o -lssl -lcrypto -o app # 正确 gcc main.o -lcrypto -lssl -o app # 错误!可能找不到符号 ``` 因为 `libssl.a` 依赖 `libcrypto.a`,所以 `libcrypto.a` 必须放在后面。 手动链接时也一样: ```bash gcc main.c /usr/lib/x86_64-linux-gnu/libssl.a /usr/lib/x86_64-linux-gnu/libcrypto.a -o app ``` --- ### 3. 静态库体积大? 是正常的。`.a` 是所有 `.o` 文件的打包集合,未去除无用代码。 可以用 `ar` 和 `strip` 减小体积,或使用链接时优化: ```bash gcc -s -Wl,--gc-sections -ffunction-sections -fdata-sections ... ``` --- ## ✅ 总结 你现在拥有: - ✅ **两套 OpenSSL 静态库**:分别用于 x86_64 和 ARM - ✅ 可以根据目标平台选择合适的 `.a` 文件进行链接 - ✅ 需配合对应的头文件目录(`-I/path/to/include`) - ✅ 避免混用不同来源的头文件与库,防止兼容性问题 --- ###
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值