1. 程式人生 > >(轉載)Linux 除錯技術

(轉載)Linux 除錯技術

在 Linux 上找出並解決程式錯誤的主要方法

Steve Best([email protected]
JFS 核心小組成員,IBM

您可以用各種方法來監控執行著的使用者空間程式:可以為其執行偵錯程式並單步除錯該程式,
新增列印語句,或者新增工具來分析程式。本文描述了幾種可以用來除錯在 Linux 上執行的
程式的方法。我們將回顧四種除錯問題的情況,這些問題包括段錯誤,記憶體溢位和洩漏,還
有掛起。
本文討論了四種除錯 Linux 程式的情況。在第 1 種情況中,我們使用了兩個有記憶體分配問
題的樣本程式,使用 MEMWATCH 和 Yet Another Malloc Debugger(YAMD)工具來除錯它們
。在第 2 種情況中,我們使用了 Linux 中的 strace 實用程式,它能夠跟蹤系統呼叫和信
號,從而找出程式發生錯誤的地方。在第 3 種情況中,我們使用 Linux 核心的 Oops 功能
來解決程式的段錯誤,並向您展示如何設定核心原始碼級偵錯程式(kernel source level de
bugger,kgdb),以使用 GNU 偵錯程式(GNU debugger,gdb)來解決相同的問題;kgdb 程式
是使用序列連線的 Linux 核心遠端 gdb。在第 4 種情況中,我們使用 Linux 上提供的魔術
鍵控順序(magic key sequence)來顯示引發掛起問題的元件的資訊。

常見除錯方法
當您的程式中包含錯誤時,很可能在程式碼中某處有一個條件,您認為它為真(true),但實
際上是假(false)。找出錯誤的過程也就是在找出錯誤後推翻以前一直確信為真的某個條件
過程。

以下幾個示例是您可能確信成立的條件的一些型別:

在原始碼中的某處,某變數有特定的值。
在給定的地方,某個結構已被正確設定。
對於給定的 if-then-else 語句,if 部分就是被執行的路徑。
當子例程被呼叫時,該例程正確地接收到了它的引數。

找出錯誤也就是要確定上述所有情況是否存在。如果您確信在子例程被呼叫時某變數應該有
特定的值,那麼就檢查一下情況是否如此。如果您相信 if 結構會被執行,那麼也檢查一下
情況是否如此。通常,您的假設都會是正確的,但最終您會找到與假設不符的情況。結果,
您就會找出發生錯誤的地方。

除錯是您無法逃避的任務。進行除錯有很多種方法,比如將訊息列印到螢幕上、使用偵錯程式
,或只是考慮程式執行的情況並仔細地揣摩問題所在。

在修正問題之前,您必須找出它的源頭。舉例來說,對於段錯誤,您需要了解段錯誤發生在
程式碼的哪一行。一旦您發現了程式碼中出錯的行,請確定該方法中變數的值、方法被呼叫的方
式以及關於錯誤如何發生的詳細情況。使用偵錯程式將使找出所有這些資訊變得很簡單。如果
沒有偵錯程式可用,您還可以使用其它的工具。(請注意,產品環境中可能並不提供偵錯程式,
而且 Linux 核心沒有內建的偵錯程式。)

實用的記憶體和核心工具
您可以使用 Linux 上的除錯工具,通過各種方式跟蹤使用者空間和核心問題。請使用下面的工
具和技術來構建和除錯您的原始碼:
使用者空間工具:

記憶體工具:MEMWATCH 和 YAMD
strace
GNU 偵錯程式(gdb)
魔術鍵控順序

核心工具:

核心原始碼級偵錯程式(kgdb)
內建核心偵錯程式(kdb)
Oops


本文將討論一類通過人工檢查程式碼不容易找到的問題,而且此類問題只在很少見的情況下存
在。記憶體錯誤通常在多種情況同時存在時出現,而且您有時只能在部署程式之後才能發現內
存錯誤。

第 1 種情況:記憶體除錯工具
C 語言作為 Linux 系統上標準的程式語言給予了我們對動態記憶體分配很大的控制權。然而,
這種自由可能會導致嚴重的記憶體管理問題,而這些問題可能導致程式崩潰或隨時間的推移導
致效能降級。

記憶體洩漏(即 malloc() 記憶體在對應的 free() 呼叫執行後永不被釋放)和緩衝區溢位(例
如對以前分配到某陣列的記憶體進行寫操作)是一些常見的問題,它們可能很難檢測到。這一
部分將討論幾個除錯工具,它們極大地簡化了檢測和找出記憶體問題的過程。

MEMWATCH
MEMWATCH 由 Johan Lindh 編寫,是一個開放原始碼 C 語言記憶體錯誤檢測工具,您可以自己
下載它(請參閱本文後面部分的參考資料)。只要在程式碼中新增一個頭檔案並在 gcc 語句中
定義了 MEMWATCH 之後,您就可以跟蹤程式中的記憶體洩漏和錯誤了。MEMWATCH 支援 ANSI C
,它提供結果日誌紀錄,能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、
沒有釋放的記憶體(unfreed memory)、溢位和下溢等等。

清單 1. 記憶體樣本(test1.c)
#include
#include
#include "memwatch.h"

int main(void)
{
char *ptr1;
char *ptr2;

ptr1 = malloc(512);
ptr2 = malloc(512);

ptr2 = ptr1;
free(ptr2);
free(ptr1);
}

清單 1 中的程式碼將分配兩個 512 位元組的記憶體塊,然後指向第一個記憶體塊的指標被設定為指
向第二個記憶體塊。結果,第二個記憶體塊的地址丟失,從而產生了記憶體洩漏。

現在我們編譯清單 1 的 memwatch.c。下面是一個 makefile 示例:

test1
gcc -DMEMWATCH -DMW_STDIO test1.c memwatch
c -o test1

當您執行 test1 程式後,它會生成一個關於洩漏的記憶體的報告。清單 2 展示了示例 memwa
tch.log 輸出檔案。

清單 2. test1 memwatch.log 檔案
MEMWATCH 2.67 Copyright (C) 1992-1999 Johan Lindh

...
double-free: <4> test1.c(15), 0x80517b4 was freed from test1.c(14)
...
unfreed: <2> test1.c(11), 512 bytes at 0x80519e4
{FE FE FE FE FE FE FE FE FE FE FE FE ..............}

Memory usage statistics (global):
N)umber of allocations made: 2
L)argest memory usage : 1024
T)otal of all alloc() calls: 1024
U)nfreed bytes totals : 512

MEMWATCH 為您顯示真正導致問題的行。如果您釋放一個已經釋放過的指標,它會告訴您。對
於沒有釋放的記憶體也一樣。日誌結尾部分顯示統計資訊,包括洩漏了多少記憶體,使用了多少
記憶體,以及總共分配了多少記憶體。

YAMD
YAMD 軟體包由 Nate Eldredge 編寫,可以查詢 C 和 C++ 中動態的、與記憶體分配有關的問
題。在撰寫本文時,YAMD 的最新版本為 0.32。請下載 yamd-0.32.tar.gz(請參閱參考資料
)。執行 make 命令來構建程式;然後執行 make install 命令安裝程式並設定工具。

一旦您下載了 YAMD 之後,請在 test1.c 上使用它。請刪除 #include memwatch.h 並對 m
akefile 進行如下小小的修改:

使用 YAMD 的 test1
gcc -g test1.c -o test1

清單 3 展示了來自 test1 上的 YAMD 的輸出。

清單 3. 使用 YAMD 的 test1 輸出
YAMD version 0.32
Executable: /usr/src/test/yamd-0.32/test1
...
INFO: Normal allocation of this block
Address 0x40025e00, size 512
...
INFO: Normal allocation of this block
Address 0x40028e00, size 512
...
INFO: Normal deallocation of this block
Address 0x40025e00, size 512
...
ERROR: Multiple freeing At
free of pointer already freed
Address 0x40025e00, size 512
...
WARNING: Memory leak
Address 0x40028e00, size 512
WARNING: Total memory leaks:
1 unfreed allocations totaling 512 bytes

*** Finished at Tue ... 10:07:15 2002
Allocated a grand total of 1024 bytes 2 allocations
Average of 512 bytes per allocation
Max bytes allocated at one time: 1024
24 K alloced internally / 12 K mapped now / 8 K max
Virtual program size is 1416 K
End.

YAMD 顯示我們已經釋放了記憶體,而且存在記憶體洩漏。讓我們在清單 4 中另一個樣本程式上
試試 YAMD。

清單 4. 記憶體程式碼(test2.c)
#include
#include

int main(void)
{
char *ptr1;
char *ptr2;
char *chptr;
int i = 1;
ptr1 = malloc(512);
ptr2 = malloc(512);
chptr = (char *)malloc(512);
for (i; i <= 512; i++) {
chptr[i] = 'S';
}
ptr2 = ptr1;
free(ptr2);
free(ptr1);
free(chptr);
}

您可以使用下面的命令來啟動 YAMD:

./run-yamd /usr/src/test/test2/test2
清單 5 顯示了在樣本程式 test2 上使用 YAMD 得到的輸出。YAMD 告訴我們在 for 迴圈中
有“越界(out-of-bounds)”的情況。

清單 5. 使用 YAMD 的 test2 輸出
Running /usr/src/test/test2/test2
Temp output to /tmp/yamd-out.1243
*********
./run-yamd: line 101: 1248 Segmentation fault (core dumped)
YAMD version 0.32
Starting run: /usr/src/test/test2/test2
Executable: /usr/src/test/test2/test2
Virtual program size is 1380 K
...
INFO: Normal allocation of this block
Address 0x40025e00, size 512
...
INFO: Normal allocation of this block
Address 0x40028e00, size 512
...
INFO: Normal allocation of this block
Address 0x4002be00, size 512
ERROR: Crash
...
Tried to write address 0x4002c000
Seems to be part of this block:
Address 0x4002be00, size 512
...
Address in question is at offset 512 (out of bounds)
Will dump core after checking heap.
Done.

MEMWATCH 和 YAMD 都是很有用的除錯工具,它們的使用方法有所不同。對於 MEMWATCH,您
需要新增包含檔案 memwatch.h 並開啟兩個編譯時間標記。對於連結(link)語句,YAMD 只
需要 -g 選項。

Electric Fence
多數 Linux 分發版包含一個 Electric Fence 包,不過您也可以選擇下載它。Electric Fe
nce 是一個由 Bruce Perens 編寫的 malloc() 除錯庫。它就在您分配記憶體後分配受保護的
記憶體。如果存在 fencepost 錯誤(超過陣列末尾執行),程式就會產生保護錯誤,並立即結
束。通過結合 Electric Fence 和 gdb,您可以精確地跟蹤到哪一行試圖訪問受保護記憶體。
Electric Fence 的另一個功能就是能夠檢測記憶體洩漏。

第 2 種情況:使用 strace
strace 命令是一種強大的工具,它能夠顯示所有由使用者空間程式發出的系統呼叫。strace
顯示這些呼叫的引數並返回符號形式的值。strace 從核心接收資訊,而且不需要以任何特殊
的方式來構建核心。將跟蹤資訊傳送到應用程式及核心開發者都很有用。在清單 6 中,分割槽
的一種格式有錯誤,清單顯示了 strace 的開頭部分,內容是關於調出建立檔案系統操作(
mkfs)的。strace 確定哪個呼叫導致問題出現。

清單 6. mkfs 上 strace 的開頭部分
execve("/sbin/mkfs.jfs", ["mkfs.jfs", "-f", "/dev/test1"], &
...
open("/dev/test1", O_RDWR|O_LARGEFILE) = 4
stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0
ioctl(4, 0x40041271, 0xbfffe128) = -1 EINVAL (Invalid argument)
write(2, "mkfs.jfs: warning - cannot setb" ..., 98mkfs.jfs: warning -
cannot set blocksize on block device /dev/test1: Invalid argument )
= 98
stat64("/dev/test1", {st_mode=&, st_rdev=makedev(63, 255), ...}) = 0
open("/dev/test1", O_RDONLY|O_LARGEFILE) = 5
ioctl(5, 0x80041272, 0xbfffe124) = -1 EINVAL (Invalid argument)
write(2, "mkfs.jfs: can/'t determine device"..., ..._exit(1)
= ?

清單 6 顯示 ioctl 呼叫導致用來格式化分割槽的 mkfs 程式失敗。ioctl BLKGETSIZE64 失敗
。(BLKGET-SIZE64 在呼叫 ioctl 的原始碼中定義。) BLKGETSIZE64 ioctl 將被新增到 L
inux 中所有的裝置,而在這裡,邏輯卷管理器還不支援它。因此,如果 BLKGETSIZE64 ioc
tl 呼叫失敗,mkfs 程式碼將改為呼叫較早的 ioctl 呼叫;這使得 mkfs 適用於邏輯卷管理器

第 3 種情況:使用 gdb 和 Oops
您可以從命令列使用 gdb 程式(Free Software Foundation 的偵錯程式)來找出錯誤,也可
以從諸如 Data Display Debugger(DDD)這樣的幾個圖形工具之一使用 gdb 程式來找出錯
誤。您可以使用 gdb 來除錯使用者空間程式或 Linux 核心。這一部分只討論從命令列執行 g
db 的情況。

使用 gdb program name 命令啟動 gdb。gdb 將載入可執行程式符號並顯示輸入提示符,讓
您可以開始使用偵錯程式。您可以通過三種方式用 gdb 檢視程序:

使用 attach 命令開始檢視一個已經執行的程序;attach 將停止程序。


使用 run 命令執行程式並從頭開始除錯程式。


檢視已有的核心檔案來確定程序終止時的狀態。要檢視核心檔案,請用下面的命令啟動 gdb

gdb programname corefilename
要用核心檔案進行除錯,您不僅需要程式的可執行檔案和原始檔,還需要核心檔案本身。要
用核心檔案啟動 gdb,請使用 -c 選項:

gdb -c core programname

gdb 顯示哪行程式碼導致程式發生核心轉儲。

在執行程式或連線到已經執行的程式之前,請列出您覺得有錯誤的原始碼,設定斷點,然後
開始除錯程式。您可以使用 help 命令檢視全面的 gdb 線上幫助和詳細的教程。

kgdb
kgdb 程式(使用 gdb 的遠端主機 Linux 核心偵錯程式)提供了一種使用 gdb 除錯 Linux 內
核的機制。kgdb 程式是核心的擴充套件,它讓您能夠在遠端主機上執行 gdb 時連線到執行用 k
gdb 擴充套件的核心機器。您可以接著深入到核心中、設定斷點、檢查資料並進行其它操作(類
似於您在應用程式上使用 gdb 的方式)。這個補丁的主要特點之一就是執行 gdb 的主機在
引導過程中連線到目標機器(執行要被除錯的核心)。這讓您能夠儘早開始除錯。請注意,
補丁為 Linux 核心添加了功能,所以 gdb 可以用來除錯 Linux 核心。

使用 kgdb 需要兩臺機器:一臺是開發機器,另一臺是測試機器。一條序列線(空調製解調
器電纜)將通過機器的串列埠連線它們。您希望除錯的核心在測試機器上執行;gdb 在開發機
器上執行。gdb 使用序列線與您要除錯的核心通訊。

請遵循下面的步驟來設定 kgdb 除錯環境:


下載您的 Linux 核心版本適用的補丁。


將元件構建到核心,因為這是使用 kgdb 最簡單的方法。(請注意,有兩種方法可以構建多
數核心元件,比如作為模組或直接構建到核心中。舉例來說,日誌紀錄檔案系統(Journale
d File System,JFS)可以作為模組構建,或直接構建到核心中。通過使用 gdb 補丁,我們
就可以將 JFS 直接構建到核心中。)


應用核心補丁並重新構建核心。


建立一個名為 .gdbinit 的檔案,並將其儲存在核心原始檔子目錄中(換句話說就是 /usr/
src/linux)。檔案 .gdbinit 中有下面四行程式碼:
set remotebaud 115200
symbol-file vmlinux
target remote /dev/ttyS0
set output-radix 16


將 append=gdb 這一行新增到 lilo,lilo 是用來在引導核心時選擇使用哪個核心的引導載
入程式。
image=/boot/bzImage-2.4.17
label=gdb2417
read-only
root=/dev/sda8
append="gdb gdbttyS=1 gdb-baud=115200 nmi_watchdog=0"

清單 7 是一個指令碼示例,它將您在開發機器上構建的核心和模組引入測試機器。您需要修改
下面幾項:


[email protected]:使用者標識和機器名。
/usr/src/linux-2.4.17:核心原始碼樹的目錄。
bzImage-2.4.17:測試機器上將引導的核心名。
rcp 和 rsync:必須允許它在構建核心的機器上執行。

清單 7. 引入測試機器的核心和模組的指令碼
set -x
rcp [email protected]: /usr/src/linux-2.4.17/arch/i386/boot/bzImage /boot/bzImage-2.4.17
rcp [email protected]:/usr/src/linux-2.4.17/System.map /boot/System.map-2.4.17
rm -rf /lib/modules/2.4.17
rsync -a [email protected]:/lib/modules/2.4.17 /lib/modules
chown -R root /lib/modules/2.4.17
lilo

現在我們可以通過改為使用核心原始碼樹開始的目錄來啟動開發機器上的 gdb 程式了。在本
示例中,核心原始碼樹位於 /usr/src/linux-2.4.17。輸入 gdb 啟動程式。

如果一切正常,測試機器將在啟動過程中停止。輸入 gdb 命令 cont 以繼續啟動過程。一個
常見的問題是,空調變解調器電纜可能會被連線到錯誤的串列埠。如果 gdb 不啟動,將埠改
為第二個串列埠,這會使 gdb 啟動。

使用 kgdb 除錯核心問題
清單 8 列出了 jfs_mount.c 檔案的原始碼中被修改過的程式碼,我們在程式碼中建立了一個空
指標異常,從而使程式碼在第 109 行產生段錯誤。

清單 8. 修改過後的 jfs_mount.c 程式碼
int jfs_mount(struct super_block *sb)
{
...
int ptr; /* line 1 added */
jFYI(1, ("/nMount JFS/n"));
/ *
* read/validate superblock
* (initialize mount inode from the superblock)
* /
if ((rc = chkSuper(sb))) {
goto errout20;
}
108 ptr=0; /* line 2 added */
109 printk("%d/n",*ptr); /* line 3 added */

清單 9 在向檔案系統發出 mount 命令之後顯示一個 gdb 異常。kgdb 提供了幾條命令,如
顯示資料結構和變數值以及顯示系統中的所有任務處於什麼狀態、它們駐留在何處、它們在
哪些地方使用了 CPU 等等。清單 9 將顯示回溯跟蹤為該問題提供的資訊;where 命令用來
執行反跟蹤,它將告訴被執行的呼叫在程式碼中的什麼地方停止。

清單 9. gdb 異常和反跟蹤
mount -t jfs /dev/sdb /jfs

Program received signal SIGSEGV, Segmentation fault.
jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
109 printk("%d/n",*ptr);
(gdb)where
#0 jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
#1 0xc01a0dbb in jfs_read_super ... at super.c:280
#2 0xc0149ff5 in get_sb_bdev ... at super.c:620
#3 0xc014a89f in do_kern_mount ... at super.c:849
#4 0xc0160e66 in do_add_mount ... at namespace.c:569
#5 0xc01610f4 in do_mount ... at namespace.c:683
#6 0xc01611ea in sys_mount ... at namespace.c:716
#7 0xc01074a7 in system_call () at af_packet.c:1891
#8 0x0 in ?? ()
(gdb)

下一部分還將討論這個相同的 JFS 段錯誤問題,但不設定偵錯程式,如果您在非 kgdb 核心環
境中執行清單 8 中的程式碼,那麼它使用核心可能生成的 Oops 訊息。

Oops 分析
Oops(也稱 panic,慌張)訊息包含系統錯誤的細節,如 CPU 暫存器的內容。在 Linux 中
,除錯系統崩潰的傳統方法是分析在發生崩潰時傳送到系統控制檯的 Oops 訊息。一旦您掌
握了細節,就可以將訊息傳送到 ksymoops 實用程式,它將試圖將程式碼轉換為指令並將堆疊
值對映到核心符號。在很多情況下,這些資訊就足夠您確定錯誤的可能原因是什麼了。請注
意,Oops 訊息並不包括核心檔案。

讓我們假設系統剛剛建立了一條 Oops 訊息。作為編寫程式碼的人,您希望解決問題並確定什
麼導致了 Oops 訊息的產生,或者您希望向顯示了 Oops 訊息的程式碼的開發者提供有關您的
問題的大部分資訊,從而及時地解決問題。Oops 訊息是等式的一部分,但如果不通過 ksym
oops 程式執行它也於事無補。下面的圖顯示了格式化 Oops 訊息的過程。

格式化 Oops 訊息


ksymoops 需要幾項內容:Oops 訊息輸出、來自正在執行的核心的 System.map 檔案,還有
 /proc/ksyms、vmlinux 和 /proc/modules。關於如何使用 ksymoops,核心原始碼 /usr/s
rc/linux/Documentation/oops-tracing.txt 中或 ksymoops 手冊頁上有完整的說明可以參
考。Ksymoops 反彙編程式碼部分,指出發生錯誤的指令,並顯示一個跟蹤部分表明程式碼如何被
呼叫。

首先,將 Oops 訊息儲存在一個檔案中以便通過 ksymoops 實用程式執行它。清單 10 顯示
了由安裝 JFS 檔案系統的 mount 命令建立的 Oops 訊息,問題是由清單 8 中新增到 JFS
安裝程式碼的那三行程式碼產生的。

清單 10. ksymoops 處理後的 Oops 訊息
ksymoops 2.4.0 on i686 2.4.17. Options used
... 15:59:37 sfb1 kernel: Unable to handle kernel NULL pointer dereference at
virtual address 0000000
... 15:59:37 sfb1 kernel: c01588fc
... 15:59:37 sfb1 kernel: *pde = 0000000
... 15:59:37 sfb1 kernel: Oops: 0000
... 15:59:37 sfb1 kernel: CPU: 0
... 15:59:37 sfb1 kernel: EIP: 0010:[jfs_mount+60/704]

... 15:59:37 sfb1 kernel: Call Trace: [jfs_read_super+287/688]
[get_sb_bdev+563/736] [do_kern_mount+189/336] [do_add_mount+35/208]
[do_page_fault+0/1264]
... 15:59:37 sfb1 kernel: Call Trace: [ ]...
... 15:59:37 sfb1 kernel: [
... 15:59:37 sfb1 kernel: Code: 8b 2d 00 00 00 00 55 ...

>>EIP; c01588fc <=====
...
Trace; c0106cf3
Code; c01588fc
00000000 <_EIP>:
Code; c01588fc <=====
0: 8b 2d 00 00 00 00 mov 0x0,%ebp <=====
Code; c0158902
6: 55 push %ebp

接下來,您要確定 jfs_mount 中的哪一行程式碼引起了這個問題。Oops 訊息告訴我們問題是
由位於偏移地址 3c 的指令引起的。做這件事的辦法之一是對 jfs_mount.o 檔案使用 objd
ump 實用程式,然後檢視偏移地址 3c。Objdump 用來反彙編模組函式,看看您的 C 原始碼
會產生什麼彙編指令。清單 11 顯示了使用 objdump 後您將看到的內容,接著,我們檢視
jfs_mount 的 C 程式碼,可以看到空值是第 109 行引起的。偏移地址 3c 之所以很重要,是
因為 Oops 訊息將該處標識為引起問題的位置。

清單 11. jfs_mount 的彙編程式清單
109 printk("%d/n",*ptr);

objdump jfs_mount.o

jfs_mount.o: file format elf32-i386

Disassembly of section .text:

00000000 :
0:55 push %ebp
...
2c: e8 cf 03 00 00 call 400
31: 89 c3 mov %eax,%ebx
33: 58 pop %eax
34: 85 db test %ebx,%ebx
36: 0f 85 55 02 00 00 jne 291
3c: 8b 2d 00 00 00 00 mov 0x0,%ebp << problem line above
42: 55 push %ebp

kdb
Linux 核心偵錯程式(Linux kernel debugger,kdb)是 Linux 核心的補丁,它提供了一種在
系統能執行時對核心記憶體和資料結構進行檢查的辦法。請注意,kdb 不需要兩臺機器,不過
它也不允許您像 kgdb 那樣進行原始碼級別上的除錯。您可以新增額外的命令,給出該資料
結構的標識或地址,這些命令便可以格式化和顯示基本的系統資料結構。目前的命令集允許
您控制包括以下操作在內的核心操作:


處理器單步執行
執行到某條特定指令時停止
當存取(或修改)某個特定的虛擬記憶體位置時停止
當存取輸入/輸出地址空間中的暫存器時停止
對當前活動的任務和所有其它任務進行堆疊回溯跟蹤(通過程序 ID)
對指令進行反彙編

追擊記憶體溢位

您肯定不想陷入類似在幾千次呼叫之後發生分配溢位這樣的情形。

我們的小組花了許許多多時間來跟蹤稀奇古怪的記憶體錯誤問題。應用程式在我們的開發工作
站上能執行,但在新的產品工作站上,這個應用程式在呼叫 malloc() 兩百萬次之後就不能
運行了。真正的問題是在大約一百萬次呼叫之後發生了溢位。新系統之所有存在這個問題,
是因為被保留的 malloc() 區域的佈局有所不同,從而這些零散記憶體被放置在了不同的地方
,在發生溢位時破壞了一些不同的內容。

我們用多種不同技術來解決這個問題,其中一種是使用偵錯程式,另一種是在原始碼中新增跟
蹤功能。在我職業生涯的大概也是這個時候,我便開始關注記憶體除錯工具,希望能更快更有
效地解決這些型別的問題。在開始一個新專案時,我最先做的事情之一就是執行 MEMWATCH
和 YAMD,看看它們是不是會指出記憶體管理方面的問題。

記憶體洩漏是應用程式中常見的問題,不過您可以使用本文所講述的工具來解決這些問題。

第 4 種情況:使用魔術鍵控順序進行回溯跟蹤
如果在 Linux 掛起時您的鍵盤仍然能用,那請您使用以下方法來幫助解決掛起問題的根源。
遵循這些步驟,您便可以顯示當前執行的程序和所有使用魔術鍵控順序的程序的回溯跟蹤。
 


您正在執行的核心必須是在啟用 CONFIG_MAGIC_SYS-REQ 的情況下構建的。您還必須處在文
本模式。CLTR+ALT+F1 會使您進入文字模式,CLTR+ALT+F7 會使您回到 X Windows。
當在文字模式時,請按 ,然後按 。上述魔術的擊鍵會分別給出當前執行的程序和所有程序
的堆疊跟蹤。
請查詢 /var/log/messages。如果一切設定正確,則系統應該已經為您轉換了核心的符號地
址。回溯跟蹤將被寫到 /var/log/messages 檔案中。

結束語
幫助除錯 Linux 上的程式有許多不同的工具可供使用。本文講述的工具可以幫助您解決許多
編碼問題。能顯示記憶體洩漏、溢位等等的位置的工具可以解決記憶體管理問題,我發現 MEMWA
TCH 和 YAMD 很有幫助。

使用 Linux 核心補丁會使 gdb 能在 Linux 核心上工作,這對解決我工作中使用的 Linux
的檔案系統方面的問題很有幫助。此外,跟蹤實用程式能幫助確定在系統呼叫期間檔案系統
實用程式什麼地方出了故障。下次當您要擺平 Linux 中的錯誤時,請試試這些工具中的某一
個。

參考資料

下載 MEMWATCH。


下載 YAMD。


下載 ElectricFence。


請檢視 Dynamic Probes 除錯功能程式。


請閱讀文章“Linux software debugging with GDB”。(developerWorks,2001 年 2 月)
 


請訪問 IBM Linux Technology Center。


在 developerWorks Linux 專區可以找到更多的 Linux 文章。

關於作者
Steve Best 在位於德克薩斯州奧斯汀的 IBM Linux Technology Center 工作。目前,他在
做 Linux 專案的日誌紀錄檔案系統(Journaled File System,JFS)的工作。Steve 在操作
系統方面有豐富的從業經驗,他的著重的領域是檔案系統、國際化和安全性。

相關推薦

轉載Linux 除錯技術

在 Linux 上找出並解決程式錯誤的主要方法 Steve Best([email protected]) JFS 核心小組成員,IBM 您可以用各種方法來監控執行著的使用者空間程式:可以為其執行偵錯程式並單步除錯該程式,新增列印語句,或者新增工具來分析程式。本

轉載服務端技術選型

發布 elong 令行 成了 執行效率 body nal work develop 原文地址:http://xielong.me/2015/04/17/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8A%80%E6%9C%AF%E9%80%89%E5%9E%

轉載Linux下getopt()函式的使用

步入正題: 我們的主角----getopt()函式。 英雄不問出處,getopt()函式的出處就是unistd.h標頭檔案(哈哈),寫程式碼的時候千萬不要忘記把他老人家include上。 再來看一下這傢伙的原型(不是六耳獼猴): int getopt(int

轉載linux命令之四十五crontab命令

        at 命令是針對僅執行一次的任務,迴圈執行的例行性計劃任務,linux系統則是由 cron (crond) 這個系統服務來控制的。Linux 系統上面原本就有非常多的計劃性工作,因此這個系統服務是預設啟動的。另外,由於使用者自己也可以設定計劃任務,所以 Linux 系統也提供了使用者控制計劃

轉載Linux下的 ARM裸機除錯環境搭建(GDB + JLink)

一直想擺脫windows環境,在純linux下進行arm裸機開發,但是由於一直不知道JLink如何在linux下執行和配置,一直無法進行下去。以前都是windows+AXD除錯。包括本人用的FL2440開發板和JLink偵錯程式也沒有提供在linux除錯的文件。前些天由於想

linux最大文件句柄數量總結轉載

指定 which 非root cti 文件打開 可能 查看 mit value   最近部署上線的一個引擎,啟動之後內存、日誌顯示一切正常,但是外部無法進行引擎訪問。幾經周折,在同事的協助下,找出了問題:root用戶的open files為1024,引擎啟動時,1024個文

Linux下安裝Python3的django並配置mysql作為django默認數據庫轉載

make lba del log pri ica www src rim 我的操作系統為centos6.5 1 首先選擇django要使用什麽數據庫。django1.10默認數據庫為sqlite3,本人想使用mysql數據庫,但為了測試方便順便要安裝一下sqlite開發

手把手教你玩轉 CSS3 3D 技術轉載

是不是 col 默認 占滿 概念 ebe 說明 adb relative css3的3d起步 要玩轉css3的3d,就必須了解幾個詞匯,便是透視(perspective)、旋轉(rotate)和移動(translate)。透視即是以現實的視角來看屏幕上的2D事物,從而展現3

linux 將一個服務器上的文件或文件夾拷貝到另一個服務器上轉載

轉載 oca href 計算機名稱 http 目錄命令 遠程服務器 target blog 復制文件或目錄命令: 復制文件: (1)將本地文件拷貝到遠程 scp 文件名用戶名@計算機IP或者計算機名稱:遠程路徑 本地192.168.1.8客戶端 scp /r

Linux下MySQL的安裝和啟動轉載

enable linu char cal mysql用戶 客戶端程序 ast 初學 unix 原文鏈接:http://www.linuxidc.com/Linux/2016-07/133234.htm 一、MySQL各類安裝方法的比較 在Linux系統下,MySQL有3種主

深入理解Flink核心技術轉載

優點 流程圖 align 優化器 red 興趣 hdf 定義 lin 作者:李呈祥 Flink項目是大數據處理領域最近冉冉升起的一顆新星,其不同於其他大數據項目的諸多特性吸引了越來越多的人關註Flink項目。本文將深入分析Flink一些關鍵的技術與特性,希望能夠幫助讀者對

linux c/c++ GDB教程詳解轉載

spec -h AS 不同的 argv 路徑 scheme execution ram 學習使用了GDB一段時間後,發現它真的好強大!好用! GDB是GNU開源組織發布的一個強大的UNIX下的程序調試工具。或許,各位比較喜歡那種圖形界面方式的,像VC、BCB等IDE的調試,

軟件性能測試技術----Linux服務器性能

bsp 分析 處理方法 性能測試 linux ron j2e 跳轉 實時 全圖: 測試目的: 測試範圍&性能指標: 測試與生產環境服務器配置不同的處理方法: 實時CPU監控: 實時內存監控: 實時網絡監控: 實時磁盤監控: 萬能命令: Linux

linux上udev的配置轉載

val ts包 possible prim 識別 服務 出了 ble == udev配置文件主要的udev配置文件是/etc/udev/udev.conf。這個文件通常很短,他可能只是包含幾行#開頭的註釋,然後有幾行選項:udev_rules=”/etc/ude

Linux塊設備IO子系統(一) _驅動模型轉載

validate per ring span () VC isp 設備 思路   塊設備是Linux三大設備之一,其驅動模型主要針對磁盤,Flash等存儲類設備,塊設備(blockdevice)是一種具有一定結構的隨機存取設備,對這種設備的讀寫是按塊(所以叫塊設備)進行的,

linuxlinux 環境下 安裝禪道轉載 -- 跟web服務器無關,無視apache、nginx!!!

sdn php 修改 鏈接 net 壓縮 操作 tps 數據庫 參考文章 鏈接 :https://blog.csdn.net/xinxin19881112/article/details/46813991 講的非常完美、透徹,不像其他的文章,都是抄襲的,沒一點註意事項和自己

成為一名阿里P7Java架構師需要的技術準備轉載

最近部門招聘,很多工程師,包括我在內都參與了內推和麵試的過程,經過這次招聘,我發現能夠最終拿到offer的人,基本上在看到簡歷的那一瞬間就已經定下來了,後續的面試只不過是一種驗證而已(注意,是驗證,而不是走過場),除非你面試過程中犯錯誤,或者你不想來,否則,那個offer一定是可以拿下的。 那些拿下offe

linux基本命令很全的轉載

Ubuntu的圖形介面使用起來非常方便,但是要想對Linux熟練掌握,就必須學會它的操作命令。雖然可能會花費一些時間,不過從長遠的角度來說,這的確是一件事半功倍的事情,它會讓我們更瞭解Linux,更靈活地去使用Linux。 Ubuntu提供了很多命令,不過在本章中不

Jmeter 十二除錯工具之--Debug Processor轉載

      前置處理器或後置處理器中的 Debug Processor,也是常用的一個除錯工具,其可以獲取樣本執行緒的相關資訊進行展示,可通過檢視結果樹中的響應資料檢視對應樣本執行緒請求、響應及變數等資訊。在檢視的時候注意 Debug PostProcessor的檢視作用域

Linux -----wget 命令轉載

Linux wget是一個下載檔案的工具,它用在命令列下。對於Linux使用者是必不可少的工具,尤其對於網路管理員,經常要下載一些軟體或從遠端伺服器恢復備份到本地伺服器。如果我們使用虛擬主機,處理這樣的事務我們只能先從遠端伺服器下載到我們電腦磁碟,然後再用ftp工具上傳到伺服器。這樣既浪費時間又浪費精力,那不