参考手册
小技巧
- 读取内核全局变量的值(参考)
# bpftrace -qe 'BEGIN {printf("banner: %s\ntotalram: 0x%lx\n", str(kaddr("linux_banner")), *kaddr("_totalram_pages")); exit();}' banner: Linux version 5.19.0+ (pengdl@ubuntu) (gcc (Ubuntu 9.4.0-1ubunt totalram: 0xd3178
- 抓取地址被写时的调用栈 (参考)
当排查内核中某个变量被谁在哪个位置修改时,可以使用这个方法。变量的地址可以根据/proc/kallsyms或者crash工具或者bpftrace或者内核日志来获得
- 自定义结构体
对于无法直接访问的内核结构体,可以用下面的方法自定义一个数据结构来获取自己关心的字段的值。
#!/usr/bin/env bpftrace /* struct worker_pool { [0x0] spinlock_t lock; [0x4] int cpu; [0x8] int node; [0xc] int id; [0x10] unsigned int flags; [0x18] unsigned long watchdog_ts; [0x20] struct list_head worklist; [0x30] int nr_workers; [0x34] int nr_idle; [0x38] struct list_head idle_list; [0x48] struct timer_list idle_timer; [0x90] struct timer_list mayday_timer; [0xd8] struct hlist_head busy_hash[64]; [0x2d8] struct worker *manager; [0x2e0] struct list_head workers; [0x2f0] struct completion *detach_completion; [0x2f8] struct ida worker_ida; [0x310] struct workqueue_attrs *attrs; [0x318] struct hlist_node hash_node; [0x328] int refcnt; [0x340] atomic_t nr_running; [0x348] struct callback_head rcu; } */ union worker_pool { struct { char rsv0[0xc]; int id; }; struct { char rsv1[0x30]; int nr_workers; int nr_idle; }; struct { char rsv2[0x340]; int nr_running; }; }; struct worker { char rsv0[0x40]; union worker_pool *pool; }; kprobe:create_worker { $wp = (union worker_pool *)arg0; if ($wp->id == 4) { printf("%s: nr_worker: %d, nr_idle: %d, nr_running: %d, %s\n", func, $wp->nr_workers, $wp->nr_idle, $wp->nr_running, kstack); } } kprobe:destroy_worker { $wp = ((struct worker *)arg0)->pool; if ($wp->id == 4) { time(); printf(" %s: nr_worker: %d, nr_idle: %d, nr_running: %d, %s\n", func, $wp->nr_workers, $wp->nr_idle, $wp->nr_running, kstack); } }
内存泄漏
kmemleak.bt源码
用法:./kmemleak.bt [槽位数]