continue
【 模塊調(diào)試 】
『 內(nèi)聯(lián)函數(shù) 』
對(duì)于模塊的步驟是有些不同的,因?yàn)槟K目標(biāo)文件中是不包含絕對(duì)地址的。
( 步驟的相關(guān)說(shuō)明和實(shí)例將被添加 http://kgdb.linsyssoft.com/inlinemodules.htm )
『 卸載和裝載模塊 』
同第三節(jié)的相關(guān)內(nèi)容
『 loadmodule.sh的工作 』
相關(guān)內(nèi)容只針對(duì)kgdb1.8或早些的。
---目標(biāo)文件段---
假設(shè)是 trfs 模塊目標(biāo)文件。文件中包含的段可以使用 objdump 來(lái)列出。
$ objdump -h trfs
trfs: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000162c 00000000 00000000 00000040 2**4
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
1 .text.lock 0000010a 00000000 00000000 0000166c 2**0
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
2 .rodata 000002a4 00000000 00000000 00001780 2**5
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 __ksymtab 00000020 00000000 00000000 00001a24 2**2
CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
4 .kstrtab 0000006f 00000000 00000000 00001a60 2**5
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .modinfo 00000111 00000000 00000000 00001acf 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
6 .data 00000178 00000000 00000000 00001be0 2**5
CONTENTS, ALLOC, LOAD, RELOC, DATA
7 .bss 00000010 00000000 00000000 00001d58 2**2
ALLOC
8 .stab 0003b8b0 00000000 00000000 00001d58 2**2
CONTENTS, RELOC, READONLY, DEBUGGING
9 .stabstr 000e32bd 00000000 00000000 0003d608 2**0
CONTENTS, READONLY, DEBUGGING
10 .comment 000001ab 00000000 00000000 001208c5 2**0
CONTENTS, READONLY
11 .note 0000008c 00000010 00000010 00120a70 2**0
CONTENTS, READONLY
.text 是代碼段, .data 包含初始化數(shù)據(jù), .bss包含 未初始化數(shù)據(jù)。調(diào)試信息包含在 .stab 和 .stabstr段中。
VMA 是 段的虛擬地址。因?yàn)槲募晕粗囟ㄎ,所?所有段的VMAs都為 0 。
內(nèi)核目標(biāo)文件--vmlinux ,被重定位。所以vmlinux中段的VMAs出現(xiàn)在進(jìn)程虛擬地址空間的地方,擁有實(shí)際地址。
$ objdump -h vmlinux
vmlinux: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0014ed2b c0100000 c0100000 00001000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .text.lock 00009579 c024ed30 c024ed30 0014fd30 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 00048061 c02582c0 c02582c0 001592c0 2**5
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .kstrtab 0000a200 c02a0340 c02a0340 001a1340 2**5
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 __ex_table 00001848 c02aa540 c02aa540 001ab540 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 __ksymtab 000023f0 c02abd88 c02abd88 001acd88 2**2
CONTENTS, ALLOC, LOAD
, READONLY, DATA
6 .data 0001a200 c02ae180 c02ae180 001af180 2**5
CONTENTS, ALLOC, LOAD, DATA
7 .data.init_task 00002000 c02ca000 c02ca000 001ca000 2**5
CONTENTS, ALLOC, LOAD, DATA
8 .text.init 00018718 c02cc000 c02cc000 001cc000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
9 .data.init 0001ed18 c02e4720 c02e4720 001e4720 2**5
CONTENTS, ALLOC, LOAD, DATA
10 .setup.init 00000170 c0303440 c0303440 00203440 2**2
CONTENTS, ALLOC, LOAD, DATA
11 .initcall.init 000000bc c03035b0 c03035b0 002035b0 2**2
CONTENTS, ALLOC, LOAD, DATA
12 .data.page_aligned 00000800 c0304000 c0304000 00204000 2**5
CONTENTS, ALLOC, LOAD, DATA
13 .data.cacheline_aligned 00004520 c0304800 c0304800 00204800 2**5
CONTENTS, ALLOC, LOAD, DATA
14 .bss 00041f54 c0308d20 c0308d20 00208d20 2**5
ALLOC
15 .stab 00615708 00000000 00000000 00208d20 2**2
CONTENTS, READONLY, DEBUGGING
16 .stabstr 001b4ec1 00000000 00000000 0081e428 2**0
CONTENTS, READONLY, DEBUGGING
17 .comment 00005bfa 00000000 00000000 009d32e9 2**0
CONTENTS, READONLY
18 .note 00001e28 c034ac74 c034ac74 009d8ee3 2**0
CONTENTS, READONLY
如以上輸出所見(jiàn),代碼段.text ,開(kāi)始于 地址 0xc0100000。
『 裝載模塊 』
當(dāng)模塊裝載進(jìn)內(nèi)核,其首先被重定位。模塊的重定位意思是將所有相對(duì)地址轉(zhuǎn)化為絕對(duì)地址。
模塊重定位后,insmod 命令打印模塊map文件,如果命令行需要的話。
模塊map文件包含 模塊中的段和所有符號(hào)的地址。
模塊trfs的部分模塊map文件如下所示:
$ head -n 20 /tmp/trfs.map
Sections: Size Address Align
.this 00000060 c1808000 2**2
.text 0000162c c1808060 2**4
.text.lock 0000010a c180968c 2**0
.rodata 000002a4 c18097a0 2**5
__ksymtab 00000048 c1809a44 2**2
.kstrtab 00000109 c1809aa0 2**5
.data 00000178 c1809bc0 2**5
.bss 00000010 c1809d38 2**2
__archdata 00000000 c1809d50 2**4
Symbols:
00000000 a translators.c
00000000 a linkinfo.c
00000000 a view.c
00000000 a super.c
00000000 a dirinfo.c
00000000 a link.c
00000000 a dir.c
c1808000 d __this_module
代碼段.text在地址0xc1808060處裝入。
『 gdb腳本的產(chǎn)生 』
loadmodule.sh產(chǎn)生一個(gè)gdb腳本,用于裝載目標(biāo)文件到gdb中。
腳本告訴gdb裝載模塊目標(biāo)文件,給出不同段裝載之處的地址。
以上模塊map的gdb腳本如下:
$ cat /mnt/work/gdbscripts/loadtrfs
add-symbol-file /mnt/work/build/old-pc/trfs/modules/trfs/trfs 0xc1808060 -s .text.lock 0xc180968c -s .rodata 0xc18097a0 -s __ksymtab
0xc1809a44 -s .data 0xc1809bc0
loadmodule.sh 從模塊map文件中獲得段的地址。
--將目標(biāo)文件載入gdb --
含有地址的模塊目標(biāo)文件載入后,gdb可以計(jì)算一個(gè)符號(hào)的地址,通過(guò)提供相對(duì)地址給包含此符號(hào)的段的絕對(duì)地址來(lái)實(shí)現(xiàn)。
例如 trfs模塊中有一個(gè)函數(shù) tr_initviewtree 。 包含他以及函數(shù)相對(duì)地址的段,可以通過(guò) objdump 來(lái)找到。
$ objdump -t trfs | grep tr_initviewtree
000014f0 g F .text 00000016 tr_initviewtree
.text 是包含此函數(shù)的段,字符 F 表示其是一個(gè)函數(shù),0x14f0 是此函數(shù)在.text段中的相對(duì)地址。0x16是此函數(shù)的代碼長(zhǎng)度。
此函數(shù)載入的地址是0xc1808060 + 0x14f0 = 0xc1809550。
此地址在模塊目標(biāo)文件中也給出了。
$ grep tr_initviewtree /tmp/trfs.map
c1809550 T tr_initviewtree
$ gdbmod
GNU gdb 20000204
Copyright 2000 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
(gdb) source loadtrfs
add symbol table from file "/mnt/work/build/old-pc/trfs/modules/trfs/trfs" at
.text_addr = 0xc1808060
.text.lock_addr = 0xc180968c
.rodata_addr = 0xc18097a0
__ksymtab_addr = 0xc1809a44
.data_addr = 0xc1809bc0
(gdb) p tr_initviewtree
$1 = {void ()} 0xc1809550
『 init_module()之調(diào)試 』
從一個(gè)模塊中調(diào)試init_module()函數(shù)需要特殊的步驟。
當(dāng)gdb被模塊通報(bào)( 針對(duì)kgdb 1.9之后的 ),或者當(dāng)loadmodule.sh結(jié)束 (針對(duì)kgdb 1.8之前的),模塊調(diào)試信息才是可用的。
init_module()函數(shù)那時(shí)已經(jīng)被執(zhí)行過(guò),因此init_module()不能通過(guò)原來(lái)的方式來(lái)調(diào)試。
方法是:在調(diào)用init_module()處之前的位置 設(shè)置斷點(diǎn)于內(nèi)核中。
對(duì)于kgdb 1.9/之后的版本:
modprobe 或者 insmod 載入模塊,等到以上斷點(diǎn)的產(chǎn)生。這時(shí)你可以在模塊中任何地方設(shè)置斷點(diǎn)了。
針對(duì)kgdb 1.8/之前的版本:
一旦內(nèi)核侵入調(diào)試器,等到loadmodule.sh退出。 此時(shí) init_module()未被調(diào)用,所有調(diào)試信息是可用的。現(xiàn)在載入模塊目標(biāo)文件。一旦載入,斷點(diǎn)可設(shè)置于模
塊中任何地方,如同init_module()的一條語(yǔ)句一般。
余下的顯示實(shí)例參見(jiàn) http://kgdb.linsyssoft.com/initmodule.htm
************************************************************************************************************************************************
【 體系依賴 】
『 x86_64 』
Kgdb patch已經(jīng)在雙opteron CPU上測(cè)試過(guò)。包括線程支持、控制臺(tái)信息的所有功能測(cè)試可用。
x86_64 gdb對(duì)運(yùn)行kgdb的CPU上d的o_IRQ函數(shù)不能正確顯示堆棧跟蹤。為了得到這個(gè)堆棧跟蹤,一個(gè)隱蔽線程被執(zhí)行。
Press Ctrl+C in gdb
Program received signal SIGTRAP, Trace/breakpoint trap.
breakpoint () at kernel/kgdbstub.c:1056
1056 atomic_set(&kgdb_setting_breakpoint, 0);
(gdb) bt
#0 breakpoint () at kernel/kgdbstub.c:1056
#1 0xffffffff801e3f17 in kgdb8250_interrupt (irq=3, dev_id=0x0, regs=0x1)
at drivers/serial/kgdb_8250.c:143
#2 0xffffffff80113341 in handle_IRQ_event (irq=3, regs=0x10001a1dc48,
action=0x1001ff29840) at arch/x86_64/kernel/irq.c:219
#3 0xffffffff801134e1 in do_IRQ (regs=0x10001a1dc48)
at arch/x86_64/kernel/irq.c:387
#4 0xffffffff80110eab in common_interrupt () at elfcore.h:92
Previous frame inner to this frame (corrupt stack?)
GDB不能正確跟蹤這一點(diǎn),檢查一下線程列表中是否包含一個(gè)隱蔽線程。其可以通過(guò)在中斷進(jìn)入點(diǎn)處的tag stack標(biāo)識(shí)。
(gdb) info thr
10 Thread 32769 (Stack at interrupt entrypoint) __delay (loops=1384000)
at arch/x86_64/lib/delay.c:30
9 Thread 32768 (Shadow task 0 for pid 0) 0xffffffff8010eb3e in cpu_idle ()
at sched.h:914
8 Thread 8 (aio/0) 0xffffffff8013f41c in worker_thread (
__startup=0x1001ff28d60) at sched.h:914
7 Thread 7 (kswapd0) kswapd (p=0xffffffff803170e8) at mm/vmscan.c:1046
6 Thread 6 (pdflush) __pdflush (my_work=0x1001fd71f18) at current.h:11
5 Thread 5 (pdflush) __pdflush (my_work=0x1001fd73f18) at current.h:11
4 Thread 4 (kblockd/0) 0xffffffff8013f41c in worker_thread (
__startup=0x1001ff28ae0) at sched.h:914
3 Thread 3 (events/0) 0xffffffff8013f41c in worker_thread (
__startup=0x1001ff3cd60) at sched.h:914
2 Thread 2 (ksoftirqd/0) ksoftirqd (__bind_cpu=0xffffffff8030be20)
at current.h:11
* 1 Thread 1 (swapper) breakpoint () at kernel/kgdbstub.c:1056
如上面的列表,這個(gè)隱蔽線程是10,我們可以從線程10中得到丟失的回溯跟蹤。
(gdb) bt
#0 __delay (loops=1384000) at arch/x86_64/lib/delay.c:30
#1 0xffffffff80212bfd in ide_delay_50ms () at drivers/ide/ide.c:1451
#2 0xffffffff8020b252 in actual_try_to_identify (drive=0xffffffff803c05e8,
cmd=236 '' '') at drivers/ide/ide-probe.c:351
#3 0xffffffff8020b67a in try_to_identify (drive=0xffffffff803c05e8,
cmd=236 '' '') at drivers/ide/ide-probe.c:405
#4 0xffffffff8020b7ef in do_probe (drive=0xffffffff803c05e8, cmd=236 ''?)
at drivers/ide/ide-probe.c:497
#5 0xffffffff8020bcaa in probe_hwif (hwif=0xffffffff803c04a0)
at drivers/ide/ide-probe.c:613
#6 0xffffffff8020bf46 in probe_hwif_init (hwif=0xffffffff803c04a0)
at drivers/ide/ide-probe.c:868
#7 0xffffffff8021a10d in ide_setup_pci_device (dev=0x1f9e8, d=0x1f7)
at drivers/ide/setup-pci.c:740
....
『 PowerPC 』
這個(gè)支持的提供還只是基于試驗(yàn)基礎(chǔ)。仍然為進(jìn)行測(cè)試,所以要小心使用。歡迎提交相關(guān)問(wèn)題報(bào)告和bug修復(fù)。
---編譯一個(gè)包括kgdb的內(nèi)核---
啟用 [ Standard / Generic serial ] 支持。如果kgdb選項(xiàng)中 通過(guò)gdb顯示控制臺(tái)信息的選項(xiàng)被選中,啟用 串口控制臺(tái)支持 。
『 Linux / s390 』
---運(yùn)行于 VM 下的 Linux/s390 的 kgdb stub (ver 0.2.0 )---
這里試圖提供有關(guān) VM下,運(yùn)行在s390平臺(tái)上的Linux的內(nèi)核源碼級(jí)調(diào)試工具。其提供的功能組和x86 kgdb很相似。
如圖:

x3270連接 s390 VM ,提供一個(gè)控制臺(tái)接口給Linux客戶機(jī)。 gdbstub.pl 通過(guò)x3270 告知VM , 并使用 VM的 調(diào)試命令 (如 cp trace 、cp dispay ......)
來(lái)實(shí)現(xiàn)gdb遠(yuǎn)程協(xié)議。
VM調(diào)試命令可用于 提取和修改 運(yùn)行沒(méi)有發(fā)生變化的內(nèi)核的Linux客戶機(jī)。
圖中的 B和C通常是相同機(jī)器。
注意:其只能工作于32位的s390平臺(tái)。64位的s390平臺(tái)還不支持,這需要全部重寫(xiě)代碼。
---必要條件---
目標(biāo)機(jī):
運(yùn)行在VM下的Linux/s390
主機(jī) :
* 運(yùn)行Linux的x86或s390
* 打有下面附加補(bǔ)丁的gdb5.2 (x86上本地的 或 交叉平臺(tái)的)。在下載頁(yè)有一個(gè)預(yù)編譯版本(x86 binary)。
* x3270。 使用基于文本的3270客戶端-c3270來(lái)取代x3270是可能的。使用只基于腳本的客戶機(jī)是不怎么可取的,因?yàn)橛袝r(shí)需要手工干預(yù)。
* stub ---- 由三個(gè)perl文件組成,gdbstub.pl 、cpinter.pl 、 cpstrings.pl
最新的發(fā)布在這里 http://sourceforge.net/projects/kgdb
---基本使用---
(交叉)編譯內(nèi)核 時(shí)加上 -g -O2 。 拷貝到你的目標(biāo)機(jī)并引導(dǎo)之。 主機(jī)則需要一份包含完整調(diào)試信息的vmlinux拷貝。
在目標(biāo)機(jī)端,你不能從標(biāo)準(zhǔn)的kernel rpm中簡(jiǎn)單地使用 一個(gè)plain(平坦)的 -O2 內(nèi)核,不能在主機(jī)端使用-g -O2的內(nèi)核。當(dāng)使用-g 選項(xiàng)時(shí),地址將有輕微的不同。
一個(gè)遺憾,因?yàn)檫@對(duì)于調(diào)試 運(yùn)行著標(biāo)準(zhǔn)發(fā)布內(nèi)核的產(chǎn)品服務(wù)器而言 是非常有用的。
編輯 cpstrings.pl 文件,以使輸出與你的VM配置相匹配。
在你解開(kāi)stub的目錄下,創(chuàng)建兩個(gè)fifo: mkfifo ip op
運(yùn)行命令:
$ sleep 1000000 > ip < op &
這個(gè)可以讓讓x3270保持“陶”醉狀態(tài)。
按照下面來(lái)啟動(dòng)x3270:
x3270 -script -port blah hostname op
注意控制臺(tái)大小至少需要80x25 。 現(xiàn)在手動(dòng)登錄到你的虛擬機(jī),啟動(dòng)編譯時(shí)帶有-g選項(xiàng)的內(nèi)核。
按照下面來(lái)運(yùn)行 stub :
perl -w ./gdbstub.pl >ip <OP
如果所有一切進(jìn)行的順利,其將迫使目標(biāo)機(jī)進(jìn)入 CP ,并釋放命令組。
在控制臺(tái)你可以進(jìn)行觀察。一旦上面結(jié)束,啟動(dòng)gdb。
s390-ibm-linux-gdb /path/to/vmlinux
set remotetimeout 20 /* 如果通過(guò)網(wǎng)絡(luò)來(lái)調(diào)試目標(biāo)機(jī),需要運(yùn)行這條命令。你可以將此 加入到 .gdbinit 中。
set trust-readonly-sections 1 /*這個(gè)可以避免一些不必要的麻煩。gdb will memory. target remote stubhost:5513
stubhost之處即是你運(yùn)行g(shù)dbstub.pl之處(通常在本地主機(jī))
你將得到下面信息:
$ s390-ibm-linux-gdb vmlinux
GNU gdb 5.2
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=i386-pc-linux-gnu --target=s390-ibm-linux"...
(gdb) set remotetimeout 20
(gdb) ta re linux-3:5513
Remote debugging using linux-3:5513
cpu_idle (unused=0x0) at process.c:76
76 }
warning: shared library handler failed to enable breakpoint
(gdb)
這時(shí)你可以設(shè)置斷點(diǎn),檢查內(nèi)存、寄存器、查看回溯跟蹤……
---線程調(diào)試---
你現(xiàn)在可以觀察所有線程任務(wù)?梢郧袚Q到特殊線程做回溯跟蹤。這對(duì)于調(diào)試死鎖等狀況是有用的。
這里有兩種方法來(lái)做。
你可以根據(jù)自己的特殊環(huán)境,選擇其中一個(gè)較簡(jiǎn)單的。
--方法1--
Helper Module :
第一步需要編譯一個(gè)調(diào)用gdbmod的helper module,然后在目標(biāo)機(jī)上載入。
你可以在任何時(shí)間來(lái)做,甚至是stub 和 gdb啟動(dòng)之后。但是,這一步需要在運(yùn)行第一個(gè)"info threads"命令之前來(lái)完成。
編輯Makefile樣品,改變諸如內(nèi)核源碼路徑、交叉編譯等等之后,gdbmod.c 文件才可以被編譯。
$ make
s390-ibm-linux-gcc -D__KERNEL__ -I/home/ganesh/work/usr/src/linux-2.4.9-37/include -Wall -Wstrict-prototypes -Wno-trigraphs -O2
-fno-omit-frame-pointer -fno-strict-aliasing -fno-common -Wno-unused -pipe -fno-strength-reduce -DMODULE -DEXPORT_SYMTAB -c
gdbmod.c
$
現(xiàn)在拷貝它至目標(biāo)機(jī):
$ scp -C gdbmod.o root@target:
gdbmod.o 100% |***************************************************| 106 KB 00:02
載入模塊:
$ ssh root@target "/sbin/insmod /root/gdbmod.o;/sbin/lsmod"
Module Size Used by
gdbmod 107616 0 (unused)
netiucv 18096 1 (autoclean)
af_packet 16560 0 (autoclean)
$
獲得目標(biāo)機(jī)的/proc/ksyms,在你的perl stub目錄下dump一下ksyms:
[......gdbstub]$ ssh root@target cat /proc/ksyms >ksyms
[......gdbstub]$
現(xiàn)在你可以運(yùn)行 info threads ,大約半分鐘之后如果目標(biāo)機(jī)連通網(wǎng)絡(luò),你應(yīng)該獲得一個(gè)運(yùn)行在目標(biāo)機(jī)上的線程列表。
使用 thread 和 bt 命令來(lái)切換 線程和回溯跟蹤。
但是,無(wú)法設(shè)置線程上下文中的變量、寄存器。 只可觀,不可觸焉。
[............gdb]$ ~/work/gdb-build/gdb/gdb
GNU gdb 5.2
[.....]
(gdb) ta re localhost:5513
cpu_idle (unused=0x0) at process.c:76
76 }
warning: shared library handler failed to enable breakpoint
(gdb) info threads
22 Thread 575 (mingetty) schedule_timeout (timeout=2147483647) at sched.c:425
21 Thread 568 (xfs) schedule_timeout (timeout=282645) at sched.c:453
20 Thread 516 (crond) schedule_timeout (timeout=231187) at sched.c:453
19 Thread 497 (xinetd) schedule_timeout (timeout=2147483647) at sched.c:425
18 Thread 464 (sshd) schedule_timeout (timeout=2147483647) at sched.c:425
17 Thread 427 (klogd) 0x0001f8d4 in do_syslog (type=0, buf=0x406b38 "", len=4095) at printk.c:178
16 Thread 422 (syslogd) schedule_timeout (timeout=2147483647) at sched.c:425
15 Thread 110 (kjournald) interruptible_sleep_on (q=0xc6d468) at sched.c:838
14 Thread 109 (kjournald) interruptible_sleep_on (q=0xc6d668) at sched.c:838
13 Thread 108 (kjournald) interruptible_sleep_on (q=0xc6d268) at sched.c:838
12 Thread 107 (kjournald) interruptible_sleep_on (q=0xc6d068) at sched.c:838
11 Thread 106 (kjournald) interruptible_sleep_on (q=0xf6a868) at sched.c:838
10 Thread 10 (mdrecoveryd) md_thread (arg=0x0) at md.c:3010
9 Thread 9 (kupdated) schedule_timeout (timeout=228645) at sched.c:453
8 Thread 8 (bdflush) interruptible_sleep_on (q=0x200c30) at sched.c:838
7 Thread 7 (kreclaimd) interruptible_sleep_on (q=0x1f9a0c) at sched.c:838
6 Thread 6 (kswapd) schedule_timeout (timeout=228682) at sched.c:453
5 Thread 5 (ksoftirqd_CPU1) ksoftirqd (__bind_cpu=0x0) at softirq.c:387
4 Thread 4 (ksoftirqd_CPU0) ksoftirqd (__bind_cpu=0x0) at softirq.c:387
3 Thread 3 (keventd) context_thread (dummy=0x0) at context.c:99
2 Thread 2 (kmcheck) __down_interruptible (sem=0x321020) at semaphore.c:128
1 Thread 1 (init) schedule_timeout (timeout=228644) at sched.c:453
(gdb) thread 17
[Switching to thread 17 (Thread 427)]#0 0x0001f8d4 in do_syslog (type=0, buf=0x406b38 "", len=4095)
at printk.c:178
178 error = wait_event_interruptible(log_wait, (log_start - log_end));
(gdb) bt 3
#0 0x0001f8d4 in do_syslog (type=0, buf=0x406b38 "", len=4095) at printk.c:178
#1 0x0007a6aa in kmsg_read (file=0x0, buf=0x0, count=0, ppos=0x0) at kmsg.c:35
#2 0x0004d5c8 in sys_read (fd=0, buf=0x406b38 "", count=4095) at read_write.c:162
(More stack frames follow...)
(gdb)
--方法2--
另一個(gè)辦法耗費(fèi)更長(zhǎng)的時(shí)間,比需要做的更加痛苦, 但是,有一個(gè)優(yōu)點(diǎn): 不需要 helper module 。
你需要在 .gdbinit 中加入用戶定義的命令兩條:
【code】
define addcontext
maintenance packet Qa,$arg0,$arg1,,
end
define findthreads
set $init_thread = init_tasks[0]
set $athread = $init_thread->next_task
while $athread != $init_thread
set $frameptr = (unsigned long *)(((unsigned long *)$athread->thread.ksp)[0])
printf "%s %x ", (char *)$athread->comm, $frameptr
set $athread = $athread->next_task
end
end
【/code】
(gdb) findthreads
init 7f5d80
kmcheck 7f1eb8
keventd df7f08
ksoftirqd_CPU0 df5f38
ksoftirqd_CPU1 df3f38
kswapd de5e48
kreclaimd de3ec0
bdflush de1eb8
kupdated ddfeb8
mdrecoveryd ddbf18
kjournald f00bea0
kjournald f003ea0
kjournald efffea0
kjournald eff9ea0
kjournald eff5ea0
syslogd e975d80
klogd eb11d80
sshd e7ffd80
xinetd e733d80
crond 1003e28
xfs e567d80
mingetty e4dfd08
(gdb) addcontext syslogd e975d80
sending: "Qa,syslogd,e975d80,,"
received: "OK"
(gdb) info threads
1 Thread 65536 (syslogd) schedule_timeout (timeout=2147483647) at sched.c:425
(gdb) thread 1
[Switching to thread 1 (Thread 65536)]#0 schedule_timeout (timeout=2147483647) at sched.c:425
425 goto out;
(gdb) bt 3
#0 schedule_timeout (timeout=2147483647) at sched.c:425
#1 0x00063178 in do_select (n=1, fds=0xe975ed8, timeout=0xe975ef0) at select.c:223
#2 0x00063548 in sys_select (n=1, inp=0x7ffff800, outp=0x0, exp=0x0, tvp=0x0) at select.c:318
(More stack frames follow...)
(gdb) addcontext klogd eb11d80
sending: "Qa,klogd,eb11d80,,"
received: "OK"
(gdb) info threads
2 Thread 65537 (klogd) 0x0001f8d4 in do_syslog (type=129048040, buf=0x406b38 "", len=4095)
at printk.c:178
* 1 Thread 65536 (syslogd) schedule_timeout (timeout=2147483647) at sched.c:425
(gdb) thread 2
[Switching to thread 2 (Thread 65537)]#0 0x0001f8d4 in do_syslog (type=129048040, buf=0x406b38 "",
len=4095) at printk.c:178
178 error = wait_event_interruptible(log_wait, (log_start - log_end));
(gdb) bt 3
#0 0x0001f8d4 in do_syslog (type=129048040, buf=0x406b38 "", len=4095) at printk.c:178
#1 0x0007a6aa in kmsg_read (file=0x7b11de8, buf=0x7b11de8 "", count=0, ppos=0x0) at kmsg.c:35
#2 0x0004d5c8 in sys_read (fd=129048040, buf=0x406b38 "", count=4095) at read_write.c:162
(More stack frames follow...)
(gdb) The program is running. Exit anyway? (y or n) y
如果gdb的偽語(yǔ)言(pseudo-language)在傳遞參數(shù)之前可以實(shí)際求出它們,這個(gè)方法就更容易一些。
然后我們可以簡(jiǎn)單地從 findthreads loop 中運(yùn)行 addcontext ,而不是手動(dòng)做這一切。
addcontext 命令也可北用于 backtrack任意幀指針,比如 一個(gè) panic 之后在控制臺(tái)上打印出的。
『 提示 』
* 不要做不受限制的backtrace ,esp 。 如果你調(diào)試的是一個(gè)非常遠(yuǎn)的系統(tǒng),Do a bt 5 or something 。
* 避免使用 n 命令 和 單步進(jìn)single stepping 。(這也許在將來(lái)會(huì)得到修復(fù))。
在必要的地方設(shè)置斷點(diǎn)。
* 在gdb上擊打 ^C 來(lái)強(qiáng)迫機(jī)器進(jìn)入調(diào)試器。作為選擇, 在控制臺(tái)鍵入 PA1 或者 #cp 將起到同樣的效果。
* 有時(shí)會(huì)發(fā)生這種情況: 機(jī)器已進(jìn)入CP ,但是 在控制臺(tái)上沒(méi)有訊息--VM Read/Running 的狀態(tài)遺留著,沒(méi)有斷點(diǎn)地址。
或者CP訊息出現(xiàn)在屏幕上。如果你懷疑機(jī)器在CP中,擊打 Enter 。This is usually sufficient to get the ball rolling.
* 當(dāng)機(jī)器進(jìn)入CP之中,你可以在控制臺(tái)運(yùn)行任何命令 而不影響調(diào)試器。 只是不要改變狀態(tài) (如 寄存器、內(nèi)存)。
* 不要在stub運(yùn)行時(shí)從控制臺(tái)手動(dòng)恢復(fù)VM。
* 你可以在任何時(shí)候殺死stub 和 gdb , do a #cpu all cp tr ,移除斷點(diǎn),重啟stub 和 gdb 。
* 你可以調(diào)試模塊,但是復(fù)雜的。我不能在這里解釋的更多。在 kgdb.sourceforge.net 上查看調(diào)試模塊說(shuō)明。
---gdb patch---
stub使用 硬件斷點(diǎn) , 所以不必要去消耗PC資源。我確信這樣做更好一些。
【patch code】
--- ./gdb/s390-tdep.c.ORG Wed Jun 5 01:59:18 2002
+++ ./gdb/s390-tdep.c Wed Jun 5 01:59:39 2002
@@ -1787,7 +1787,7 @@
/* Amount PC must be decremented by after a breakpoint.
This is often the number of bytes in BREAKPOINT
but not always. */
- set_gdbarch_decr_pc_after_break (gdbarch, 2);
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_pop_frame (gdbarch, s390_pop_frame);
/* Stack grows downward. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);