1. 程式人生 > >linux CONFIG_DEBUG_OBJECTS 用法

linux CONFIG_DEBUG_OBJECTS 用法

該選項用來開啟debugobjects模組,對應核心程式碼中的debugobjects.c,
這個模組是個通用的除錯框架,用來跟蹤object的生命週期。
kernel中已有的應用該功能的object有timer,workqueue等,
當然自己也可以定義自己的模組使用這個除錯功能。


一個object有下面幾種狀態:
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,
};


對外提供的幾個介面如下,這幾個介面用於檢測當前object狀態是否正常,
比如debug_object_activate檢查object是否處於active狀態,如果object還未init或者
已經deactive,就報警告資訊。
extern void debug_object_init      (void *addr, struct debug_obj_descr *descr);
extern void
debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr);
extern void debug_object_activate  (void *addr, struct debug_obj_descr *descr);
extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
extern void debug_object_destroy   (void *addr, struct debug_obj_descr *descr);
extern void debug_object_free      (void *addr, struct debug_obj_descr *descr);
extern void debug_object_assert_init(void *addr, struct debug_obj_descr *descr);


下面看下具體程式碼實現。




/**
 * debug_object_init - debug checks when an object is initialized
 * @addr:address of the object
 * @descr:pointer to an object specific debug description structure
 */
 /*
 用於告知object已被初始化 , 當該object正在被使用 , 或者是之前已被銷燬 , 
 那麼debugobject會給出warning , 同時 , 如果外部模組提供修正介面 , 
 debugobject會嘗試修正 . 當然如果該object是第一次初始化 , 
 那麼debugobject會將其狀態置位已初始化 . 這裡需要注意的是 , 
 該介面用於那些分配在heap上的object , 如果debugobject發現該object 在呼叫者的stack上 , 
 同樣會給出warning .
 */
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;


fill_pool();//填充poll


db = get_bucket((unsigned long) addr);//獲取bucket


raw_spin_lock_irqsave(&db->lock, flags);


obj = lookup_object(addr, db);//從bucket中查詢obj
if (!obj) {//查詢失敗就重新申請一個object
obj = alloc_object(addr, db, descr);
if (!obj) {
debug_objects_enabled = 0;
raw_spin_unlock_irqrestore(&db->lock, flags);
debug_objects_oom();//分配記憶體失敗的話,需要釋放靜態申請的obj
return;
}
debug_object_is_on_stack(addr, onstack);
}


switch (obj->state) {
case ODEBUG_STATE_NONE:
case ODEBUG_STATE_INIT:
case ODEBUG_STATE_INACTIVE:
obj->state = ODEBUG_STATE_INIT;
break;
//obj處於active時,再呼叫此函式就會報警告資訊
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:   // init一個已經銷燬的obj
debug_print_object(obj, "init");
break;
default:
break;
}


raw_spin_unlock_irqrestore(&db->lock, flags);
}
//obj_pool是儲存obj node hash list,
//這個函式檢查如果初始化申請的obj數量少於ODEBUG_POOL_MIN_LEVEL,就會繼續
//申請object,然後加入obj_pool中
static void fill_pool(void)
{
gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
struct debug_obj *new;
unsigned long flags;


if (likely(obj_pool_free >= ODEBUG_POOL_MIN_LEVEL))
return;


if (unlikely(!obj_cache))
return;
//pool中obj數量過少就會申請新的obj並加入pool中
while (obj_pool_free < ODEBUG_POOL_MIN_LEVEL) {


new = kmem_cache_zalloc(obj_cache, gfp);
if (!new)
return;


kmemleak_not_leak(new);
raw_spin_lock_irqsave(&pool_lock, flags);
hlist_add_head(&new->node, &obj_pool);
obj_pool_free++;
raw_spin_unlock_irqrestore(&pool_lock, flags);
}
}


/*
 * We use the pfn of the address for the hash. That way we can check
 * for freed objects simply by checking the affected bucket.
 */
//計算object地址對應的hash值,同一個page內的addr,計算出來的hash值相同
//object hash後儲存在bucket list中,便於後續查詢
static struct debug_bucket *get_bucket(unsigned long addr)
{
unsigned long hash;
//同一個page內的addr,計算出來的hash值相同
hash = hash_long((addr >> ODEBUG_CHUNK_SHIFT), ODEBUG_HASH_BITS);
return &obj_hash[hash];
}


/*
 * Lookup an object in the hash bucket.
 */
 //bucket中查詢某個object
static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
{
struct debug_obj *obj;
int cnt = 0;


hlist_for_each_entry(obj, &b->list, node) {
cnt++;
if (obj->object == addr)
return obj;
}
if (cnt > debug_objects_maxchain)
debug_objects_maxchain = cnt;


return NULL;
}


//從obj_pool中去第一個obj使用,給obj賦值,同時將obj加入hash對應的bucket list中
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   = hlist_entry(obj_pool.first, typeof(*obj), node);


obj->object = addr;
obj->descr  = descr;
obj->state  = ODEBUG_STATE_NONE;
obj->astate = 0;
hlist_del(&obj->node);


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;
}


//這個函式用的比較多,用來列印object state 衝突資訊
static void debug_print_object(struct debug_obj *obj, char *msg)
{
struct debug_obj_descr *descr = obj->descr;
static int limit;


if (limit < 5 && descr != descr_test) {
void *hint = descr->debug_hint ?
descr->debug_hint(obj->object) : NULL;
limit++;
WARN(1, KERN_ERR "ODEBUG: %s %s (active state %u) "
"object type: %s hint: %pS\n",
msg, obj_states[obj->state], obj->astate,
descr->name, hint);
}
debug_objects_warnings++;
}
總結來看就是初始化時先申請了512個obj,加入到obj_pool,需要用到obj時就從
obj_pool中取,然後用user定義的object地址計算hash值,將obj加入到對應的bucket hash list中。


其他幾個介面用法類似,簡單描述下介面用法,就不再詳細分析程式碼了。


/**
 * debug_object_activate - debug checks when an object is activated
 * @addr:address of the object
 * @descr:pointer to an object specific debug description structure
 */
 /*
 告知object正在被使用 , 如果該object已經被使用 , 或者之前已被銷燬, 
 那麼debugobject會給出warning , 並嘗試修正 
 */
void debug_object_activate(void *addr, struct debug_obj_descr *descr)
 
/**
 * debug_object_deactivate - debug checks when an object is deactivated
 * @addr:address of the object
 * @descr:pointer to an object specific debug description structure
 */
 /*
 告知object停止使用 , 如果該object已經被停用 , 或者已被銷燬 , 
 那麼debugobject會給出warning
 */
void debug_object_deactivate(void *addr, struct debug_obj_descr *descr)




/**
 * debug_object_destroy - debug checks when an object is destroyed
 * @addr:address of the object
 * @descr:pointer to an object specific debug description structure
 */
 /*
 告知object被銷燬 , 如果該object正在被使用 , 或者已被銷燬 , 
 那麼會給出warning , 並嘗試修正該錯誤 


 */
void debug_object_destroy(void *addr, struct debug_obj_descr *descr)




/**
 * debug_object_free - debug checks when an object is freed
 * @addr:address of the object
 * @descr:pointer to an object specific debug description structure
 */
 /*
 告知object被釋放 , 如果該object正在被使用 ,
 那麼會給出warning , 並嘗試修正該錯誤 . 
 同時該介面還會將object在中 的記錄移除


 */
void debug_object_free(void *addr, struct debug_obj_descr *descr)