eBPF 核心技术与实战
倪朋飞
资深 Linux 专家,Kubernetes 项目维护者
10452 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已更新 26 讲/共 37 讲
eBPF 核心技术与实战
15
15
1.0x
00:00/00:00
登录|注册

09 | 用户态跟踪:如何使用eBPF排查应用程序?

你好,我是倪朋飞。
前面两讲,我带你梳理了查询 eBPF 跟踪点的常用方法,并以短时进程的跟踪为例,通过 bpftrace、BCC 和 libbpf 等三种方法实现了短时进程的跟踪程序。学完这些内容,我想你已经可以根据自己的实际需求,查询到内核跟踪点或内核函数,并自己开发一个 eBPF 内核跟踪程序。
也许你想问:我们能不能利用与跟踪内核状态类似的方法,去跟踪用户空间的进程呢?答案是肯定的。只要把内核态跟踪使用的  kprobe  和  tracepoint  替换成  uprobe ,或者用户空间定义的静态跟踪点(User Statically Defined Tracing,简称 USDT),并找出用户进程需要跟踪的函数,作为 eBPF 程序的挂载点,你就可以去跟踪用户进程的内部状态。
那具体该怎么做呢?今天,我就带你一起来看看,如何使用 eBPF 去跟踪用户进程的执行状态。

如何查询用户进程跟踪点?

07 讲 中我曾提到,在跟踪内核的状态之前,你需要利用内核提供的调试信息查询内核函数、内核跟踪点以及性能事件等。类似地,在跟踪应用进程之前,你也需要知道这个进程所对应的二进制文件中提供了哪些可用的跟踪点。那么,从哪里可以找到这些信息呢?如果你使用 GDB 之类的应用调试过程序,这时应该已经想到了,那就是应用程序二进制文件中的调试信息
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了使用eBPF技术跟踪应用程序执行状态的方法。作者首先介绍了查询用户进程跟踪点的方法,包括利用调试信息查询内核函数、内核跟踪点以及性能事件等。然后,作者讨论了编程语言对eBPF跟踪的影响,指出不同类型的编程语言对跟踪过程和难度有所不同。接着,文章以Bash为例,详细介绍了如何跟踪编译型语言应用程序的执行状态。通过安装Bash的调试信息并查询符号表,读者可以了解如何使用eBPF来跟踪Bash中执行的命令。此外,文章还介绍了跟踪解释型语言应用程序和即时编译型语言应用程序的方法。总的来说,本文通过实例深入浅出地介绍了eBPF技术在跟踪应用程序执行状态方面的应用,对读者了解eBPF技术具有一定的参考价值。文章内容涵盖了eBPF技术的具体应用案例,以及使用BCC和libbpf等工具进行eBPF程序开发的实际步骤,为读者提供了实用的技术指导和操作方法。通过本文的阅读,读者可以快速了解eBPF技术在应用程序跟踪方面的潜在价值和实际操作方法。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《eBPF 核心技术与实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(14)

  • 最新
  • 精选
  • 莫名
    1. 跟踪编译型语言应用程序以 Bash Shell 作为例子,觉得有些容易与解释型语言混淆。解释型语言的特征是解释程序自身为编译型程序,利用自身内置的函数进行语法分析和执行,Bash readline 函数的功能即是如此。以编译型语言 Golang helloworld 程序使用 uprobes 或者开源的 Nginx 使用 USDT 可能更恰当一些。 2. 思考题完整的 BCC 追踪程序: ----------- python_functions.c ------------- #include <uapi/linux/ptrace.h> struct data_t { char filename[128]; char funcname[64]; int lineno; }; BPF_PERF_OUTPUT(events); int print_functions(struct pt_regs *ctx) { uint64_t argptr; struct data_t data = { }; bpf_usdt_readarg(1, ctx, &argptr); bpf_probe_read_user(&data.filename, sizeof(data.filename), (void *)argptr); bpf_usdt_readarg(2, ctx, &argptr); bpf_probe_read_user(&data.funcname, sizeof(data.funcname), (void *)argptr); bpf_usdt_readarg(3, ctx, &data.lineno); events.perf_submit(ctx, &data, sizeof(data)); return 0; }; ----------- python_functions.py ------------- #!/usr/bin/python3 import sys from bcc import BPF, USDT if len(sys.argv) < 2: print("Usage: %s <tracee_pid>" % sys.argv[0]) sys.exit(1) u = USDT(pid=int(sys.argv[1])) u.enable_probe(probe="function__entry", fn_name="print_functions") b = BPF(src_file="python_functions.c", usdt_contexts=[u]) def print_event(cpu, data, size): event = b["events"].event(data) printb("%-9s %-6d %s" % (event.filename, event.lineno, event.funcname)) print("%-9s %-6s %s" % ("FILENAME", "LINENO", "FUNCTION")) b["events"].open_perf_buffer(print_event) while True: try: b.perf_buffer_poll() except KeyboardInterrupt: exit()

    作者回复: 1. 其实最终还是要看跟踪的目的是什么:如果是要排查Bash内部的执行过程,那就是跟踪编译型语言;但要是排查SHELL脚本的执行过程,那就变成了跟踪解释性语言。 2. 非常棒的答案!

    2022-02-04
    10
  • ZR2021
    老师,跟踪用户态程序的时候还有512字节的限制吗

    作者回复: eBPF 栈空间的限制跟要跟跟踪的事件是没关系的,但其实都可以通过映射避免内存限制的问题。

    2022-02-04
    2
    4
  • Geek3340
    sudo apt install bash-dbgsym 命令,执行后找不到dbgsym包的,可以参考这篇文章 https://cloud.tencent.com/developer/article/1637887

    作者回复: 👍 谢谢分享安装步骤

    2022-03-20
    2
  • Geek_59a6f9
    用户态进程跟踪是不是使用frida效果更好?

    作者回复: 嗯嗯,展示效果都是可以在用户态程序中去自定义的。

    2022-02-04
    1
  • 郑小凯
    老师,咨询下ibm jdk,使用bcc的话有办法么?

    作者回复: BCC提供了一些Java的工具 https://github.com/iovisor/bcc/tree/master/tools(java开头的工具),你可以试试看

    2022-12-21归属地:浙江
  • │.Sk
    老师您好,请教一下 1. 执行了 strip 命令删除了 .symtab 的二进制文件,是否就“不能”用 .symtab 里的符号执行 bpftrace -e 'uretprobe:/usr/bin/bash:符号 {...}' ? 2. 如果 1. 中的理解是对的,那么上面的 /usr/bin/bash 的 .symtab 实际已经被 strip 了,但是还能执行上面的 trace 是否是因为 BCC 会用 /usr/bin/bash 的 build id 去 /usr/lib/debug/.build-id/ 关联相应的符号表,然后再用符号找到函数地址? 谢谢老师!

    作者回复: 是的

    2022-03-05
  • 王恒
    某线程CPU占用率过高,通过perf工具生成了该线程的火焰图。发现该线程的系统函数占比较高,但是又无法查到这些系统函数的调用堆栈。(火焰图中,ia32_sysenter_target函数占比约6%,sysexit_from_sys_call函数占比约9%。) 特别想搞懂这些内核函数是什么时候被调用的,调用堆栈是怎么样的,为什么耗时这么久。所以特地来学习ebpf,希望边学边解决工作中的实际问题。

    作者回复: 嗯 这时候可以跟踪一下相关函数的内核调用栈

    2022-03-05
    3
  • Geek_722e86
    老师, 除了符号表之外,理论上你可以把 uprobe 插桩到二进制文件的任意地址。不过这要求你对应用程序 ELF 格式的地址空间非常熟悉,并且具体的地址会随着应用的迭代更新而发生变化。所以,在需要跟踪地址的场景中,一定要记得去 ELF 二进制文件动态获取地址信息。 ----------- 请问, 这个应该怎么操作呢? 加入我OS上的bash就是没有符号信息。 我还是想挂载readline函数,怎么办呢? # 挂载uretprobeb.attach_uretprobe(name="/usr/bin/bash", sym="readline", fn_name="bash_readline") 这个参数具体是怎么写? sudo bpftrace -e 'uretprobe:/usr/bin/bash:readline { printf("User %d executed \"%s\" command\n", uid, str(retval)); }' 这个参数怎么写?
    2023-06-01归属地:中国香港
  • Bachue Zhou
    好奇这种 uprobe 是怎么做到的?只是调用应用程序里另一个函数为什么会被内核介入?如果 epbf 程序执行时间较长,是不是应用程序会等待 ebpf 执行完再继续执行?
    2023-04-04归属地:上海
  • Bachue Zhou
    其实现在的解释型脚本语言,比如 Python,Ruby 之类的语言,各自都有自己的字节码,虚拟机和 JIT,本质上和 Java 没有太大差异,只是不把字节码保存下来而已。
    2023-04-04归属地:上海
收起评论
显示
设置
留言
14
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部