linux CONFIG_DEBUG_OBJECTS 用法
阿新 • • 發佈:2019-02-04
該選項用來開啟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)
這個模組是個通用的除錯框架,用來跟蹤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)