android设备运行bcc程序报错
报错
android 设备部署好ebpf运行环境之后,运行某些bcc工具集自带的工具会导致如下错误
root@localhost:/usr/sbin# cachestat-bpfcc
Traceback (most recent call last):File "/usr/sbin/cachestat-bpfcc", line 130, in <module>if BPF.get_kprobe_functions(b'folio_account_dirtied'):~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^File "/usr/lib/python3/dist-packages/bcc/__init__.py", line 708, in get_kprobe_functionsraise eFile "/usr/lib/python3/dist-packages/bcc/__init__.py", line 704, in get_kprobe_functionswith open(avail_filter_file, "rb") as avail_filter_f:~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/sys/kernel/debug/tracing/available_filter_functions'
root@localhost:/usr/sbin#
找不到/sys/kernel/debug/tracing/available_filter_functions 文件,
root@localhost:/usr/sbin# ls -al /sys/kernel/debug/tracing/available_filter_functions
ls: cannot access '/sys/kernel/debug/tracing/available_filter_functions': No such file or directory
root@localhost:/usr/sbin#
root@localhost:/usr/sbin# ls /sys/kernel/debug/tracing
README buffer_size_kb error_log kprobe_events printk_formats set_event trace trace_options tracing_thresh
available_events buffer_total_size_kb events kprobe_profile saved_cmdlines set_event_notrace_pid trace_clock trace_pipe uprobe_events
available_tracers current_tracer free_buffer options saved_cmdlines_size set_event_pid trace_marker tracing_cpumask uprobe_profile
buffer_percent dynamic_events instances per_cpu saved_tgids timestamp_mode trace_marker_raw tracing_on
root@localhost:/usr/sbin#
目录是存在的,但是缺少这个 available_filter_functions 文件
这个文件列出了所有可以被 kprobe、tracepoint 或 perf 使用的内核函数名,是 ftrace(Function Tracer)的一部分。
- BCC 在加载 eBPF 程序时,需要验证用户提供的内核函数名是否合法。
- 它会去读取 /sys/kernel/debug/tracing/available_filter_functions 来检查这些函数是否存在于当前内核中。
- 如果找不到该文件,BCC 就无法进行函数合法性检查,从而抛出异常。
主要是因为有两个ftrace没有打开
root@localhost:/usr/sbin# zcat /proc/config.gz | grep CONFIG_KPROBE_EVENTS
CONFIG_KPROBE_EVENTS=y
root@localhost:/usr/sbin# zcat /proc/config.gz | grep CONFIG_DYNAMIC_FTRACE
root@localhost:/usr/sbin# zcat /proc/config.gz | grep CONFIG_FUNCTION_TRACER
# CONFIG_FUNCTION_TRACER is not set
root@localhost:/usr/sbin#
需要开启 CONFIG_DYNAMIC_FTRACE CONFIG_FUNCTION_TRACER 两个 tracer
解决方案
- 开启上述两个 CONFIG_XXX
- 不使用 /sys/kernel/debug/tracing/available_filter_functions 文件来获取符号, 而是使用 /proc/kallsyms 获取符号
方案一 过于麻烦, 如果仅仅是为了简单工具使用, 去打开config, 编译烧录android 可能需要耗费好几个小时的时间
这里提供一个简单 的方案二
root@localhost:/usr/sbin# python3 -c "import bcc; print(bcc.__file__)"
/usr/lib/python3/dist-packages/bcc/__init__.py
root@localhost:/usr/sbin#
root@localhost:/usr/sbin# cat /usr/lib/python3/dist-packages/bcc/__init__.py | grep available_filter_functions -C 5except IOError as e:if e.errno != errno.EPERM:raise eblacklist = set([])avail_filter_file = "%s/tracing/available_filter_functions" % DEBUGFStry:with open(avail_filter_file, "rb") as avail_filter_f:avail_filter = set([line.rstrip().split()[0] for line in avail_filter_f])except IOError as e:if e.errno != errno.EPERM:
root@localhost:/usr/sbin#
直接把 抛出异常的 代码屏蔽掉即可, 这个文件后续会使用 /proc/kallsyms 中的符号去验证
root@localhost:/usr/sbin# cat /usr/lib/python3/dist-packages/bcc/__init__.py | grep available_filter_functions -C 7with open(blacklist_file, "rb") as blacklist_f:blacklist = set([line.rstrip().split()[1] for line in blacklist_f])except IOError as e:if e.errno != errno.EPERM:raise eblacklist = set([])avail_filter_file = "%s/tracing/available_filter_functions" % DEBUGFStry:with open(avail_filter_file, "rb") as avail_filter_f:avail_filter = set([line.rstrip().split()[0] for line in avail_filter_f])except IOError as e:# if e.errno != errno.EPERM:# raise eavail_filter = set([])
root@localhost:/usr/sbin#
结果
root@localhost:/usr/sbin# cachestat-bpfcc HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB809 27 0 96.77% 6 1162383 0 0 100.00% 6 116212 0 0 100.00% 6 116212 0 0 100.00% 6 1162392 0 0 100.00% 6 11621691 929 0 64.54% 6 11660 665 0 0.00% 6 11850 2568 0 0.00% 6 11972580 190 0 93.14% 6 11980 574 0 0.00% 6 1201630 198 0 76.09% 6 120222522 0 0 100.00% 6 120239950 749 0 98.16% 6 1206
^C 387 3165 0 10.90% 6 1218
Detaching...
root@localhost:/usr/sbin#