-
一、概述
-
debug_objects_early_init()函数用于内核的对象调试。依赖配置CONFIG_DEBUG_OBJECTS。
-
-
二、相关结构体
-
struct debug_bucket {
-
struct hlist_head list; //挂载的是当前debug_obj对象
-
raw_spinlock_t lock;
-
};
-
-
struct debug_obj {
-
struct hlist_node node; //链接跟踪器列表中的对象
-
enum debug_obj_state state; //跟踪的对象状态
-
unsigned int astate; //当前active状态
-
void *object;//对实际对象的指针
-
struct debug_obj_descr *descr; //用于调试的描述符结构体指针
-
};
-
-
enum debug_obj_state {
-
ODEBUG_STATE_NONE,
-
ODEBUG_STATE_INIT,
-
ODEBUG_STATE_INACTIVE,
-
ODEBUG_STATE_ACTIVE,
-
ODEBUG_STATE_DESTROYED,
-
ODEBUG_STATE_NOTAVAILABLE,
-
ODEBUG_STATE_MAX,
-
};
-
-
struct debug_obj_descr {
-
const char *name;
-
void *(*debug_hint) (void *addr);
-
int (*fixup_init) (void *addr, enum debug_obj_state state);
-
int (*fixup_activate) (void *addr, enum debug_obj_state state);
-
int (*fixup_destroy) (void *addr, enum debug_obj_state state);
-
int (*fixup_free) (void *addr, enum debug_obj_state state);
-
int (*fixup_assert_init)(void *addr, enum debug_obj_state state);
-
};
-
-
二、代码
-
//../lib/debugobjects.c
-
static struct debug_bucket obj_hash[ODEBUG_HASH_SIZE];
-
static HLIST_HEAD(obj_pool);
-
static struct debug_obj obj_static_pool[ODEBUG_POOL_SIZE] __initdata;
-
void __init debug_objects_early_init(void)
-
{
-
int i;
-
-
//初始化spin lock
-
for (i = 0; i < ODEBUG_HASH_SIZE; i++)
-
raw_spin_lock_init(&obj_hash[i].lock);
-
-
//将obj_static_pool数组都挂入obj_pool链表头
-
for (i = 0; i < ODEBUG_POOL_SIZE; i++)
-
hlist_add_head(&obj_static_pool[i].node, &obj_pool);
-
}
-
-
start_kernel后面在slab机制创建后,还会有debug初始化操作:
-
void __init debug_objects_mem_init(void)
-
{
-
if (!debug_objects_enabled)
-
return;
-
-
//创建debug_obj的slab高速缓存
-
obj_cache = kmem_cache_create("debug_objects_cache",sizeof (struct debug_obj), 0,SLAB_DEBUG_OBJECTS, NULL);
-
-
//obj_cache创建成功则调用debug_objects_replace_static_objects函数
-
if (!obj_cache || debug_objects_replace_static_objects()) {
-
debug_objects_enabled = 0;
-
if (obj_cache)
-
kmem_cache_destroy(obj_cache);
-
pr_warn("out of memory.\n");
-
} else
-
debug_objects_selftest(); //debug_obj对象自测
-
}
-
-
static int __init debug_objects_replace_static_objects(void)
-
{
-
struct debug_bucket *db = obj_hash;
-
struct hlist_node *tmp;
-
struct debug_obj *obj, *new;
-
HLIST_HEAD(objects);
-
int i, cnt = 0;
-
-
//从高速缓存中分配debug_obj对象挂载到全局链表objects
-
for (i = 0; i < ODEBUG_POOL_SIZE; i++) {
-
obj = kmem_cache_zalloc(obj_cache, GFP_KERNEL);
-
if (!obj)
-
goto free;
-
hlist_add_head(&obj->node, &objects);
-
}
-
-
//此时只有一个cpu在运行,关中断即进入临界区。是为了防止lockdep hell of lock ordering
-
local_irq_disable();
-
-
//从obj_pool中移除静态的debug_obj对象
-
hlist_for_each_entry_safe(obj, tmp, &obj_pool, node)
-
hlist_del(&obj->node);
-
-
//将刚分配的动态debug_obj对象链入obj_pool
-
hlist_move_list(&objects, &obj_pool);
-
-
for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
-
//将obj_hash中的debug_bucket对象上的list节点挂载的debug_obj对象链入objects链表
-
hlist_move_list(&db->list, &objects);
-
-
//然后遍历objects链表中的debug_obj对象
-
hlist_for_each_entry(obj, &objects, node) {
-
//从obj_pool取出一个debug_obj对象
-
new = hlist_entry(obj_pool.first, typeof(*obj), node);
-
//将该debug_obj对象从obj_pool链表删除
-
hlist_del(&new->node);
-
//拷贝debug_obj对象
-
*new = *obj;
-
//将该新debug_obj对象链入到objects链表中的debug_bucket对象上的list节点
-
hlist_add_head(&new->node, &db->list);
-
cnt++;
-
}
-
}
-
local_irq_enable();
-
-
pr_debug("%d of %d active objects replaced\n",cnt, obj_pool_used);
-
return 0;
-
free:
-
hlist_for_each_entry_safe(obj, tmp, &objects, node) {
-
hlist_del(&obj->node);
-
kmem_cache_free(obj_cache, obj);
-
}
-
return -ENOMEM;
-
}
-
-
三、debug使用
-
1. 定义自己用于调试的描述符结构体指针
-
static __initdata struct debug_obj_descr descr_type_test = {
-
.name = "selftest",
-
.fixup_init = fixup_init,
-
.fixup_activate = fixup_activate,
-
.fixup_destroy = fixup_destroy,
-
.fixup_free = fixup_free,
-
};
-
-
2. 初始化
-
void debug_object_init(void *addr, struct debug_obj_descr *descr)
-
{
-
if (!debug_objects_enabled)
-
return;
-
-
__debug_object_init(addr, descr, 0);
-
}
-
-
static void __debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
-
{
-
enum debug_obj_state state;
-
struct debug_bucket *db;
-
struct debug_obj *obj;
-
unsigned long flags;
-
-
//检测obj_pool是否需要添加新的debug_obj对象
-
fill_pool();
-
-
//根据要debug的地址通过hash算法得到debug_bucket对象
-
db = get_bucket((unsigned long) addr);
-
-
raw_spin_lock_irqsave(&db->lock, flags);
-
-
//根据debug地址到obj_pool查找一个debug_obj对象
-
obj = lookup_object(addr, db);
-
//没找到则通过obj_pool分配一个debug_obj对象
-
if (!obj) {
-
obj = alloc_object(addr, db, descr);
-
if (!obj) {
-
debug_objects_enabled = 0;
-
raw_spin_unlock_irqrestore(&db->lock, flags);
-
debug_objects_oom();
-
return;
-
}
-
//安全检查
-
debug_object_is_on_stack(addr, onstack);
-
}
-
-
//设置debug_obj对象状态,如果是通过alloc_object分配的对象,则状态为ODEBUG_STATE_NONE,然后通过下边设置为ODEBUG_STATE_INIT
-
switch (obj->state) {
-
case ODEBUG_STATE_NONE:
-
case ODEBUG_STATE_INIT:
-
case ODEBUG_STATE_INACTIVE:
-
obj->state = ODEBUG_STATE_INIT;
-
break;
-
-
case ODEBUG_STATE_ACTIVE:
-
debug_print_object(obj, "init");
-
state = obj->state;
-
raw_spin_unlock_irqrestore(&db->lock, flags);
-
debug_object_fixup(descr->fixup_init, addr, state);
-
return;
-
-
case ODEBUG_STATE_DESTROYED:
-
debug_print_object(obj, "init");
-
break;
-
default:
-
break;
-
}
-
-
raw_spin_unlock_irqrestore(&db->lock, flags);
-
}
-
-
static void fill_pool(void)
-
{
-
gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
-
struct debug_obj *new;
-
unsigned long flags;
-
-
//obj_pool中的空闲debug_obj对象足够则返回
-
if (likely(obj_pool_free >= ODEBUG_POOL_MIN_LEVEL))
-
return;
-
-
//若没创建高速缓存则返回
-
if (unlikely(!obj_cache))
-
return;
-
-
//若空闲对象少于最低阀值,则创建新对象链入obj_pool链表中
-
while (obj_pool_free < ODEBUG_POOL_MIN_LEVEL) {
-
new = kmem_cache_zalloc(obj_cache, gfp);
-
if (!new)
-
return;
-
-
raw_spin_lock_irqsave(&pool_lock, flags);
-
hlist_add_head(&new->node, &obj_pool);
-
obj_pool_free++;
-
raw_spin_unlock_irqrestore(&pool_lock, flags);
-
}
-
}
-
-
static struct debug_bucket *get_bucket(unsigned long addr)
-
{
-
unsigned long hash;
-
-
hash = hash_long((addr >> ODEBUG_CHUNK_SHIFT), ODEBUG_HASH_BITS);
-
return &obj_hash[hash];
-
}
-
-
static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
-
{
-
struct debug_obj *obj;
-
int cnt = 0;
-
-
//遍历该debug_bucket对象上挂载的debug_obj对象
-
hlist_for_each_entry(obj, &b->list, node) {
-
cnt++;
-
//地址相等即找到相应的debug_obj对象
-
if (obj->object == addr)
-
return obj;
-
}
-
-
//更新debug_bucket对象上挂载的debug_obj对象最大值
-
if (cnt > debug_objects_maxchain)
-
debug_objects_maxchain = cnt;
-
-
return NULL;
-
}
-
-
static struct debug_obj *alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
-
{
-
struct debug_obj *obj = NULL;
-
-
raw_spin_lock(&pool_lock);
-
if (obj_pool.first) {
-
//从obj_pool链表中取出一个debug_obj对象
-
obj = hlist_entry(obj_pool.first, typeof(*obj), node);
-
-
//对该对象初始化
-
obj->object = addr; //debug的地址
-
obj->descr = descr;//调试的描述符结构体
-
obj->state = ODEBUG_STATE_NONE;//设置状态
-
obj->astate = 0;
-
//从obj_pool链表中删除
-
hlist_del(&obj->node);
-
//链入debug_bucket对象的list节点
-
hlist_add_head(&obj->node, &b->list);
-
-
//更新一些变量
-
obj_pool_used++;
-
if (obj_pool_used > obj_pool_max_used)
-
obj_pool_max_used = obj_pool_used;
-
-
obj_pool_free--;
-
if (obj_pool_free < obj_pool_min_free)
-
obj_pool_min_free = obj_pool_free;
-
}
-
raw_spin_unlock(&pool_lock);
-
-
return obj;
-
}
-
-
3. 使能addr对应的debug_obj
-
int debug_object_activate(void *addr, struct debug_obj_descr *descr)
-
{
-
enum debug_obj_state state;
-
struct debug_bucket *db;
-
struct debug_obj *obj;
-
unsigned long flags;
-
int ret;
-
struct debug_obj o = { .object = addr,
-
.state = ODEBUG_STATE_NOTAVAILABLE,
-
.descr = descr };
-
-
//没有使能debug功能则返回
-
if (!debug_objects_enabled)
-
return 0;
-
//根据要debug的地址通过hash算法得到debug_bucket对象
-
db = get_bucket((unsigned long) addr);
-
raw_spin_lock_irqsave(&db->lock, flags);
-
-
//根据debug地址到obj_pool查找一个debug_obj对象
-
obj = lookup_object(addr, db);
-
-
//将debug_obj对象状态设置为ODEBUG_STATE_ACTIVE
-
if (obj) {
-
switch (obj->state) {
-
case ODEBUG_STATE_INIT:
-
case ODEBUG_STATE_INACTIVE:
-
obj->state = ODEBUG_STATE_ACTIVE;
-
ret = 0;
-
break;
-
-
case ODEBUG_STATE_ACTIVE:
-
debug_print_object(obj, "activate");
-
state = obj->state;
-
raw_spin_unlock_irqrestore(&db->lock, flags);
-
ret = debug_object_fixup(descr->fixup_activate, addr, state);
-
return ret ? -EINVAL : 0;
-
-
case ODEBUG_STATE_DESTROYED:
-
debug_print_object(obj, "activate");
-
ret = -EINVAL;
-
break;
-
default:
-
ret = 0;
-
break;
-
}
-
raw_spin_unlock_irqrestore(&db->lock, flags);
-
return ret;
-
}
-
-
raw_spin_unlock_irqrestore(&db->lock, flags);
-
-
if (debug_object_fixup(descr->fixup_activate, addr,ODEBUG_STATE_NOTAVAILABLE)) {
-
debug_print_object(&o, "activate");
-
return -EINVAL;
-
}
-
return 0;
-
}
-
-
-
4. 用于检查addr对应的debug_obj对象的状态是否正确
- static int __init check_results(void *addr, enum debug_obj_state state, int fixups, int warnings);