轉自:http://blog.csdn.net/larryliuqing/article/details/8674274
http://lenky.info/2013/03/10/%E5%A6%82%E4%BD%95%E7%A6%81%E6%AD%A2linux%E5%86%85%E6%A0%B8%E7%9A%84-o2%E7%BC%96%E8%AF%91%E9%80%89%E9%A1%B9/
已有各種工具可以幫助我們調試內核,比如UML、kgdb、qemu等,但比較麻煩的是gdb經常給我一個“value optimized out”的提示,而且執行的路徑與gdb的顯示也不對應,最近我在利用UML調試ext3文件系統的邏輯時就為此而感到非常麻煩(2.6.30.8的內核):
|
1
2
3
4
5
|
Breakpoint 1, journal_invalidatepage (journal=0x6c4bd800, page=0x61918b28, offset=0) at fs/jbd/transaction.c:2036
2036 {
(gdb) p bh
$2 = <value optimized out>
(gdb)
|
這應該是因為Linux內核打開gcc的-O2選項優化導致,於是我嘗試修改內核Makefile文件(/usr/src/uml/linux-2.6.30.8/Makefile):
將
|
1
2
3
4
5
|
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -Os
else
KBUILD_CFLAGS += -O2
endif
|
改為這樣(CONFIG_CC_OPTIMIZE_FOR_SIZE可以通過內核選項:General setup —> [ ] Optimize for size,進行開啟/關閉,這里不管該選項而也就統一改了):
|
1
2
3
4
5
|
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
KBUILD_CFLAGS += -O0
else
KBUILD_CFLAGS += -O0
endif
|
執行編譯,gcc給了我一個華麗的錯誤:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
[root@lenky linux-2.6.30.8]# make ARCH=um -B V=1
...
mm/built-in.o: In function `index_of':
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341: undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341: undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341: undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341: undefined reference to `__bad_size'
/usr/src/uml/linux-2.6.30.8/mm/slab.c:341: undefined reference to `__bad_size'
mm/built-in.o:/usr/src/uml/linux-2.6.30.8/mm/slab.c:341: more undefined references to `__bad_size' follow
collect2: ld returned 1
exit
status
KSYM .tmp_kallsyms1.S
nm:
'.tmp_vmlinux1'
: No such file
No valid symbol.
make: *** [.tmp_kallsyms1.S] Error 1
|
根據上面的提示信息,我嘗試把文件slab.c的編譯選項調為-O2,即編輯mm/Makefile文件,在最后加上如下一行:
|
1
2
3
4
5
6
7
|
[root@lenky linux-2.6.30.8]# vi mm/Makefile
[root@lenky linux-2.6.30.8]# tail -n 5 mm/Makefile
endif
obj-$(CONFIG_QUICKLIST) += quicklist.o
obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o
CFLAGS_slab.o = -O2
|
格式是:
CFLAGS_對應源文件[要去除通常意義上擴展名].o = gcc選項
所以上面加的是:
CFLAGS_slab.o = -O2
重新編譯:
|
1
|
[root@lenky linux-2.6.30.8]# make ARCH=um -B V=1
|
選項-B:以強制所有內核源文件全部重新編譯(因為我前面編譯過一次了,為了保險起見,就讓目標文件全部重新生成吧)
選項V=1:顯示詳細的編譯信息,而不再是簡單的“CC init/main.o”。
編譯出來的可執行程序linux比-O2的情況還小幾M,一啟動UML沒多久,果然奔潰。
看來內核里有大量的底層代碼在書寫時只兼容了-O2選項,所以如果以-O0的形式強制編譯會導致出錯,這即便不在編譯時報錯,也有極大可能會在實際執行時候出錯,完全關閉所有內核源文件的-O2編譯選項的風險太大。
退而求次,我是為了調試journal_invalidatepage()函數,那么可以僅把對應源文件transaction.c的優化選項關閉即可,這個源文件的實現在比較高的層次,關閉優化選項應該不會出錯。
編輯文件fs/jbd/Makefile,再其最后加上一行:
CFLAGS_transaction.o = -O0
重新編譯(之前的其它改動需回滾)后啟動UML,一切OK。
試試最開始的示例,用gdb綁定到UML主進程,調試函數journal_invalidatepage(),打印變量bh:
|
1
2
3
4
5
6
7
8
9
|
Breakpoint 1, journal_invalidatepage (journal=0x6c06e800, page=0x61502e30, offset=0) at fs/jbd/transaction.c:2038
2038 unsigned
int
curr_off = 0;
(gdb) p bh
$1 = (
struct
buffer_head *) 0x6bd5f0c8
(gdb) p *bh
$2 = {b_state = 3211305, b_this_page = 0x6bd5f268, b_page = 0x61501fc0, b_blocknr = 263, b_size = 1024, b_data = 0x6a648c00
""
,
b_bdev = 0x6bc02380, b_end_io = 0x600aa760 <end_buffer_async_write>, b_private = 0x6bdc46d8, b_assoc_buffers = {
next = 0x6bd5f110, prev = 0x6bd5f110}, b_assoc_map = 0x0, b_count = {counter = 2}}
(gdb)
|
嗯,效果不錯。
另外Google到由teawater提供了對應的補丁對整個內核進行關閉-O2優化,有沒有問題不知道,我暫沒有測試:
http://sourceware.org/ml/gdb/2010-12/msg00009.html
PS:
錯誤:
arch/um/os-Linux/mem.c: In function ‘create_tmp_file’:
arch/um/os-Linux/mem.c:216: error: implicit declaration of function ‘fchmod’
make[1]: *** [arch/um/os-Linux/mem.o] Error 1
make: *** [arch/um/os-Linux] Error 2
編輯文件arch/um/os-Linux/mem.c,加入頭文件:
|
1
|
#include <sys/stat.h>
|
即可。
轉載請保留地址:http://lenky.info/2013/03/10/%e5%a6%82%e4%bd%95%e7%a6%81%e6%ad%a2linux%e5%86%85%e6%a0%b8%e7%9a%84-o2%e7%bc%96%e8%af%91%e9%80%89%e9%a1%b9/ 或 http://lenky.info/?p=2238
