除錯技巧(二):BUG_ON(), WARN_ON()和panic()
阿新 • • 發佈:2018-11-26
核心中有許多地方呼叫類似BUG()的語句,它非常像一個核心執行時的斷言,意味著本來不該執行到BUG()這條語句,一旦執行即丟擲Oops。 BUG()的定義為:
#define BUG() do { \
printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
panic("BUG!"); \
} while (0)
#endif
其中的panic()定義在kernel/panic.c中,會導致核心崩潰,並列印Oops。比如arch/arm/kernel/dma.c中的enable_dma()函式:
void enable_dma (unsigned int chan)
{
dma_t *dma = dma_channel(chan);
if (!dma->lock)
goto free_dma;
if (dma->active == 0) {
dma->active = 1;
dma->d_ops->enable(chan, dma);
}
return;
free_dma:
printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan);
BUG();
}
上述程式碼的含義是,如果在dma->lock不成立的情況下,驅動直接呼叫了enable_dma(),實際上意味著核心的一個bug。
BUG()還有一個變體叫BUG_ON(),它的內部會引用BUG(),形式為
#define BUG_ON(condition) \
do { \
if (unlikely(condition)) BUG(); \
} while(0)
對於BUG_ON()而言,只有當括號內的條件成立的時候,才丟擲Oops。比如drivers/char/random.c中的類似程式碼:
static void push_to_pool(struct work_struct *work) { struct entropy_store *r = container_of(work, struct entropy_store push_work); BUG_ON(!r); _xfer_secondary_pool(r, random_read_wakeup_bits/8); trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT); r->pull->entropy_count >> ENTROPY_SHIFT); }
除了BUG_ON()外,核心有個稍微弱一些WARN_ON(),在括號中的條件成立的時候,核心會丟擲棧回溯,但是不會panic(),這通常用於核心丟擲一個警告,暗示某種不太合理的事情發生了。
如在kernel/locking/mutexdebug.c中的debug_mutex_unlock()函式發現mutex_unlock()的呼叫者和mutex_lock()的呼叫者不是同
一個執行緒的時候或者mutex的owner為空的時候,會丟擲警告資訊。
void debug_mutex_unlock(struct mutex *lock)
{
if (likely(debug_locks)) {
DEBUG_LOCKS_WARN_ON(lock->magic != lock);
if (!lock->owner)
DEBUG_LOCKS_WARN_ON(!lock->owner);
else
DEBUG_LOCKS_WARN_ON(lock->owner != current);
DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_li
mutex_clear_owner(lock);
}
}
小技巧:
WARN_ON()可以作為一個除錯技巧。比如,我們進到核心某個函式後,不知道這個函式是怎麼一級一級被呼叫進來的,那可以在該函式中加入一個WARN_ON(1)。