bpftrace使用案例学习
参考手册
小技巧
- 读取内核全局变量的值(参考)
# 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源码
#!/usr/bin/env bpftrace
t:kmem:kmalloc,
t:kmem:kmalloc_node,
t:kmem:kmem_cache_alloc,
t:kmem:kmem_cache_alloc_node
/comm != "bpftrace" /
{
$slots = 4;
if ($1 != 0) {
$slots = $1;
}
$i = 0;
while($i < $slots) {
if (args->bytes_alloc == (uint64)128 && @kmem_addr[$i] == (uint64 *)0) {
@alloc_stack[$i] = kstack;
@kmem_addr[$i] = args->ptr;
break;
}
$i++;
}
}
t:kmem:kfree,
t:kmem:kmem_cache_free
{
$slots = 4;
if ($1 != 0) {
$slots = $1;
}
$i = 0;
while($i < $slots) {
if (@kmem_addr[$i] != (uint64 *)0 && @kmem_addr[$i] == args->ptr) {
delete(@alloc_stack[$i]);
delete(@kmem_addr[$i]);
break;
}
$i++;
}
}
interval:s:5
{
time();
$slots = 4;
if ($1 != 0) {
$slots = $1;
}
$i = 0;
while($i < $slots) {
if (@kmem_addr[$i] != 0) {
printf("kmem_addr%d: 0x%lx", $i, @kmem_addr[$i]);
printf("%s\n", @alloc_stack[$i]);
}
$i++;
}
}
END {
clear(@alloc_stack);
clear(@kmem_addr);
$slots = 4;
if ($1 != 0) {
$slots = $1;
}
$i = 0;
while($i < $slots) {
delete(@alloc_stack[$i]);
delete(@kmem_addr[$i]);
$i++;
}
}
用法:./kmemleak.bt [槽位数]
语法
本文来自博客园,作者:摩斯电码,未经同意,禁止转载