本文为2007年Jim Keniston等IBM大拿的Ptrace, Utrace, Uprobes: Lightweight, Dynamic Tracing of User Apps阅读笔记

参考: 刘 明: 玩转 utrace Ptrace, Utrace, Uprobes: Lightweight, Dynamic Tracing of User Apps

1. utrace要解决的是ptrace系统调用的问题

ptrace是gdb和strace使用的系统调用, 比较老, 开销大, 对多核支持不好.
utrace提供了更强大的api, 扩展了kernel的trace debug功能.
在此基础上的uprobe, 提供了类似kprobe的, 基于breakpoint的用户态probe方法.

1.1. ptrace

ptrace的目的是debugging, 但后来也被用来tracing. 它提供:

  • 改变程序状态的能力: attach dettach进程(tracee), 单步, 断点
  • 读写进程memory的能力
  • 捕捉事件的能力: 比如系统调用或信号

ptrace慢, 不是posix标准调用, 多线程支持差, 必须变成trcee的父进程, 破环进程继承关系. 慢的很大一部分原因是, 比如gdb, 用户态的gdb要不断的调用ptrace系统调用, 造成用户态和内核态反复的切换

2. utrace

utrace的思路是, 把调试code以模块的方式, 直接放在内核态运行. 所以使用utrace接口的systemtap, 可以把.tap后缀的脚本变成.ko放到内核态运行.
utrace的监控对象是线程, 即task_struct, 用"engine"来做最基本的管理抽象. 每个utrace的client, 比如systemtap, 建立对目标thread的engine. engine提供:

  • Event reporting: utrace的client可以对感兴趣的事件注册callback, 比如系统调用
  • Thread control: utrace的client可以改变程序状态, 比如单步, 断点
  • Thread machine state access: 在client注册的callback被调用的里面, 可以检查程序的状态, 寄存器, 用户态内存.

utrace在"strategic points"上插入breakpoint指令, 被hit的时候调用其client注册的callback. 所以callback是运行在内核态的, 所以systemtap要通过ko的方式注册callback. 使用utrace后, ptrace系统调用也变成了utrace的client, 工作在内核态.

2.1. uprobe

uprobe也是utrace的client, 也被集成进了kernel. 和kprobe可以对kernel插桩类似, uprobe可以对用户进程插桩.
systemtap也是uprobe的用户, 可以指定哪个进程哪个虚拟地址要被插桩, hit了以后执行哪个handler.

uprobe设计要点

  • 支持内核模块
  • 和kprobe以及utrace协同
  • 限制小: 可以对任意个数进程, 多线程, 进行任意类型的probe; 多个client的instrument代码可以对同一个进程probe.
  • probe进程, 而不是二进制: 因为要插入breakpoint, 每个被probe的进程, 修改自己的page的拷贝来完成插入.
  • handlers可以睡眠: breakpoint被hit后, 通过signal-callback机制来运行client指定的handler, 看意思是这个进程的进程上下文, 可以睡眠;
    更进一步, 可以看这个进程的全部地址空间.
  • 性能好: 因为handler在内核态运行, 和被probe的进程同进程.
  • 多架构支持:

3. uprobe实现概要

https://landley.net/kdocs/ols/2007/ols2007v1-pages-215-224.pdf

4. utrace的性能

results matching ""

    No results matching ""