初步了解如何用GDB分析Core文件

之前初步了解過(guò)Windows 下強(qiáng)大的調(diào)試工具WinDbg足丢,也簡(jiǎn)單的整理了一個(gè)初級(jí)的文章《使用WinDbg、Map文件讨永、Dump文件定位Access Violation的代碼行》,在Linux 下面也有對(duì)應(yīng)的功能強(qiáng)大的調(diào)試工具:GDB遇革,它可以用來(lái)斷點(diǎn)調(diào)試C/C++ 的程序卿闹,也可以用于分析Linux 下的C/C++ 程序運(yùn)行崩潰產(chǎn)生的Core 文件……

另外對(duì)于GDB 工具,在《Linux gdb調(diào)試器用法全面解析》這篇文章中詳細(xì)的介紹了怎么使用GDB 去調(diào)試C/C++ 代碼

本文通過(guò)一個(gè)簡(jiǎn)單的例子展示怎么使用GDB 分析Core 文件萝快,但就像我一直強(qiáng)調(diào)的锻霎,完全停留在一個(gè)很膚淺的入門(mén)級(jí)的水平,只是先讓自己能有一個(gè)對(duì)GDB 的感性的認(rèn)知揪漩,其實(shí)GDB 很強(qiáng)大旋恼,它能做的事情遠(yuǎn)不止于本文所提到的這些皮毛

本文的內(nèi)容也是參考了網(wǎng)絡(luò)上很多的文章,然后結(jié)合自己的驗(yàn)證整理出來(lái)的

Core文件和段錯(cuò)誤

當(dāng)一個(gè)程序奔潰時(shí)冰更,在進(jìn)程當(dāng)前工作目錄的Core 文件中復(fù)制了該進(jìn)程的存儲(chǔ)圖像。Core 文件僅僅是一個(gè)內(nèi)存映像(同時(shí)加上調(diào)試信息)昂勒,主要用來(lái)調(diào)試的

通常情況下蜀细,Core 文件會(huì)包含程序運(yùn)行時(shí)的內(nèi)存、寄存器狀態(tài)戈盈、堆棧指針奠衔、內(nèi)存管理信息還有各種函數(shù)調(diào)用堆棧信息等。我們可以理解為是程序工作當(dāng)前狀態(tài)存儲(chǔ)生成第一個(gè)文件塘娶,許多程序出錯(cuò)時(shí)都會(huì)產(chǎn)生一個(gè)Core 文件归斤,通過(guò)工具分析這個(gè)文件,我們可以定位到程序異常退出時(shí)對(duì)應(yīng)的堆棧調(diào)用等信息刁岸,找出問(wèn)題所在并進(jìn)行及時(shí)解決

段錯(cuò)誤脏里,就是大名鼎鼎的Segmentation Fault,這通常是由指針錯(cuò)誤引起的难捌。簡(jiǎn)而言之膝宁,產(chǎn)生段錯(cuò)誤就是訪(fǎng)問(wèn)了錯(cuò)誤的內(nèi)存段,一般是你沒(méi)有權(quán)限根吁,或者根本就不存在對(duì)應(yīng)的物理內(nèi)存,尤其常見(jiàn)的是訪(fǎng)問(wèn)0 地址合蔽。

一般而言击敌,段錯(cuò)誤就是指訪(fǎng)問(wèn)的內(nèi)存超出了系統(tǒng)所給這個(gè)程序的內(nèi)存空間,通常這個(gè)值是由gdtr 來(lái)保存的拴事,這是一個(gè)48位的寄存器沃斤,其中的32位是保存由它指向的gdt 表圣蝎,后13位保存相應(yīng)于gdt 的下標(biāo),最后3位包括了程序是否在內(nèi)存中以及程序在CPU 中的運(yùn)行級(jí)別衡瓶。指向的gdt 是由以64位為一個(gè)單位的表徘公,在這張表中就保存著程序運(yùn)行的代碼段以及數(shù)據(jù)段的起始地址以及與此相應(yīng)的段限、頁(yè)面交換哮针、程序運(yùn)行級(jí)別关面、內(nèi)存粒度等的信息。一旦一個(gè)程序發(fā)生了越界訪(fǎng)問(wèn)十厢,CPU 就會(huì)產(chǎn)生相應(yīng)的異常保護(hù)等太,于是Segmentation fault就出現(xiàn)了

在編程中有以下幾種做法容易導(dǎo)致段錯(cuò)誤,基本都是錯(cuò)誤地使用指針引起的:

  • 訪(fǎng)問(wèn)系統(tǒng)數(shù)據(jù)區(qū)蛮放,尤其是往系統(tǒng)保護(hù)的內(nèi)存地址寫(xiě)數(shù)據(jù)缩抡,最常見(jiàn)的就是給指針以0地址
  • 內(nèi)存越界(數(shù)據(jù)越界、變量類(lèi)型不一致等)訪(fǎng)問(wèn)到不屬于你的內(nèi)存區(qū)域

程序在運(yùn)行過(guò)程中如果出現(xiàn)段錯(cuò)誤包颁,那么就會(huì)收到SIGSEGV 信號(hào)瞻想,SIGSEGV 默認(rèn)handler 的動(dòng)作是打印“段錯(cuò)誤”的出錯(cuò)信息,并產(chǎn)生Core 文件

GDB 斷點(diǎn)調(diào)試以定位錯(cuò)誤代碼行

testCrash.cpp

void testCrash()
{
    int* p = 1; //p指針指向常量1 所在的內(nèi)存地址
    *p = 3;     //將p指針指向的地址的值改為3娩嚼,
    //因?yàn)楸緛?lái)p指向一個(gè)常量内边,是不允許被修改的
    //強(qiáng)行訪(fǎng)問(wèn)系統(tǒng)保護(hù)的內(nèi)存地址就會(huì)出現(xiàn)段錯(cuò)誤
}

main.cpp

#include <stdio.h>

void testCrash();

int main()
{
    testCrash();
    return 0
}

編譯執(zhí)行,報(bào)段錯(cuò)誤

注意g++ 編譯的時(shí)候待锈,需要使用參數(shù)-g漠其,否則GDB 無(wú)法找到symbol 信息,從而無(wú)法定位問(wèn)題

image

斷點(diǎn)調(diào)試

image

很明顯竿音,在GDB 斷點(diǎn)調(diào)試的過(guò)程中和屎,已經(jīng)將錯(cuò)誤的代碼行輸出了:在testCrash.cpp 的第4行,在testCrash()方法里面春瞬,而且也將錯(cuò)誤的代碼*p = 3;打印出來(lái)了

還發(fā)現(xiàn)進(jìn)程是由于收到了SIGSEGV 信號(hào)而結(jié)束的柴信。通過(guò)進(jìn)一步的查閱文檔(man 7 signal),SIGSEGV 默認(rèn)handler 的動(dòng)作是打印”段錯(cuò)誤”的出錯(cuò)信息宽气,并產(chǎn)生Core 文件

分析Core 文件

設(shè)置Core文件大小随常,運(yùn)行程序生成Core文件

執(zhí)行ulimit -c unlimited表示不限制生成的Core 文件的大小,注意這個(gè)命令只在當(dāng)前的bash 下生效萄涯!然后運(yùn)行這個(gè)有bug 的程序绪氛,可以看到在當(dāng)前目錄下生成了core文件

image

GDB 分析Core 文件

image

同樣也是一步到位的定位到錯(cuò)誤所在的代碼行!

為了獲取更詳細(xì)的函數(shù)調(diào)用信息涝影,在執(zhí)行gdb 可執(zhí)行文件 core文件啟動(dòng)gdb后枣察,調(diào)用gdb的where或bt命令可以查看當(dāng)時(shí)的調(diào)用棧信息!確定是什么樣的函數(shù)調(diào)用棧導(dǎo)致的程序崩潰!

接著考慮下去序目,在Windows 系統(tǒng)下的運(yùn)行程序時(shí)臂痕,可能會(huì)出現(xiàn)“運(yùn)行時(shí)錯(cuò)誤”,這個(gè)時(shí)侯如果恰好你的機(jī)器上又裝有Windows 的編譯器的話(huà)猿涨,它會(huì)彈出來(lái)一個(gè)對(duì)話(huà)框握童,問(wèn)你是否進(jìn)行調(diào)試,如果你選擇是叛赚,編譯器將被打開(kāi)澡绩,并進(jìn)入調(diào)試狀態(tài),開(kāi)始調(diào)試

Linux下可以做到嗎红伦?可以讓它在SIGSEGV 的handler中調(diào)用gdb

段錯(cuò)誤時(shí)啟動(dòng)調(diào)試

testCrash.cpp

void testCrash()
{
    int* p = 1; //p指針指向常量1 所在的內(nèi)存地址
    *p = 3;     //將p指針指向的地址的值改為3英古,
    //因?yàn)楸緛?lái)p指向一個(gè)常量,是不允許被修改的
    //強(qiáng)行訪(fǎng)問(wèn)系統(tǒng)保護(hù)的內(nèi)存地址就會(huì)出現(xiàn)段錯(cuò)誤
}

main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

void testCrash();

void dump(int signo)
{
    char buf[1024];
    char cmd[1024];
    FILE *fh;

    snprintf(buf, sizeof(buf), "/proc/%d/cmdline", getpid());
    if(!(fh = fopen(buf, "r")))
    {
        exit(0);
    }
    if(!fgets(buf, sizeof(buf), fh))
    {
        exit(0);
    }
    fclose(fh);
    if(buf[strlen(buf) - 1] == '\n')
    {
        buf[strlen(buf) - 1] = '\0';
    }
    snprintf(cmd, sizeof(cmd), "gdb %s %d", buf, getpid());
    system(cmd);

    exit(0);
}

int main()
{
    signal(SIGSEGV, &dump);
    testCrash();
    return 0;
}

編譯程序

注意g++ 編譯的時(shí)候,需要使用參數(shù)-g,否則GDB 無(wú)法找到symbol 信息支子,從而無(wú)法定位問(wèn)題

image

運(yùn)行程序

首先必須要切換到root 用戶(hù)運(yùn)行,否則因?yàn)闄?quán)限問(wèn)題導(dǎo)致無(wú)法調(diào)試唠叛,另外就是進(jìn)入調(diào)試模式后執(zhí)行bt 以顯示程序的調(diào)用棧信息!

image

路漫漫其修遠(yuǎn)兮

以上展示的這些東西很簡(jiǎn)單沮稚,在你對(duì)Linux 進(jìn)程的虛擬內(nèi)存艺沼、進(jìn)程的堆棧結(jié)構(gòu)等沒(méi)有任何了解的情況下,完全照葫蘆畫(huà)瓢也能簡(jiǎn)單的使用GDB

但是上面的程序蕴掏、上面的代碼障般、上面的場(chǎng)景都完全是一個(gè)極其理想化的場(chǎng)景,在這種場(chǎng)景下排查問(wèn)題當(dāng)然是很簡(jiǎn)單的

而在實(shí)際的場(chǎng)景中盛杰,往往比這個(gè)要復(fù)雜的多

  • 程序遠(yuǎn)不止上面的十幾二十幾行挽荡,可能是上萬(wàn)、上百萬(wàn)行即供!
  • 絕不是簡(jiǎn)單的單線(xiàn)程程序定拟,可能會(huì)有多進(jìn)程、多線(xiàn)程逗嫡,這種場(chǎng)景該怎么調(diào)試青自?
  • 假如程序崩潰了,但調(diào)用的是外部提供的.so文件驱证,根本沒(méi)有對(duì)應(yīng)源碼延窜,此時(shí)就無(wú)法結(jié)合代碼分析了!
  • 假如編譯時(shí)沒(méi)有加-g 參數(shù)雷滚,那么GDB 無(wú)法找到symbol信息需曾,那怎么辦?
  • 等等等等

針對(duì)上面的這些復(fù)雜的場(chǎng)景祈远,上面展示的這些GDB 的簡(jiǎn)單招式可能就沒(méi)有效果了呆万,所以就需要更深層次的研究GDB 的使用,以及GDB 調(diào)試進(jìn)程车份、分析Core 文件背后的操作系統(tǒng)谋减、編譯原理層面的機(jī)制是什么

在Windows 下使用WinDbg 調(diào)試進(jìn)程、分析dump 文件也是一樣的情況扫沼!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末出爹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缎除,更是在濱河造成了極大的恐慌严就,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件器罐,死亡現(xiàn)場(chǎng)離奇詭異梢为,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)轰坊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)铸董,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人肴沫,你說(shuō)我怎么就攤上這事粟害。” “怎么了颤芬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵悲幅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我站蝠,道長(zhǎng)汰具,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任沉衣,我火速辦了婚禮郁副,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘豌习。我一直安慰自己存谎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布肥隆。 她就那樣靜靜地躺著既荚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪栋艳。 梳的紋絲不亂的頭發(fā)上恰聘,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼晴叨。 笑死凿宾,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的兼蕊。 我是一名探鬼主播初厚,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼孙技!你這毒婦竟也來(lái)了产禾?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤牵啦,失蹤者是張志新(化名)和其女友劉穎亚情,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體哈雏,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡楞件,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了僧著。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片履因。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盹愚,靈堂內(nèi)的尸體忽然破棺而出栅迄,到底是詐尸還是另有隱情,我是刑警寧澤皆怕,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布毅舆,位于F島的核電站,受9級(jí)特大地震影響愈腾,放射性物質(zhì)發(fā)生泄漏憋活。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一虱黄、第九天 我趴在偏房一處隱蔽的房頂上張望悦即。 院中可真熱鬧,春花似錦橱乱、人聲如沸辜梳。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)作瞄。三九已至,卻和暖如春危纫,著一層夾襖步出監(jiān)牢的瞬間宗挥,已是汗流浹背乌庶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留契耿,地道東北人瞒大。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像宵喂,于是被迫代替她去往敵國(guó)和親糠赦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子会傲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 程序調(diào)試的基本思想是“分析現(xiàn)象->假設(shè)錯(cuò)誤原因->產(chǎn)生新的現(xiàn)象去驗(yàn)證假設(shè)”這樣一個(gè)循環(huán)過(guò)程锅棕,根據(jù)現(xiàn)象如何假設(shè)錯(cuò)誤原...
    Manfred_Zone閱讀 16,541評(píng)論 0 26
  • 一、溫故而知新 1. 內(nèi)存不夠怎么辦 內(nèi)存簡(jiǎn)單分配策略的問(wèn)題地址空間不隔離內(nèi)存使用效率低程序運(yùn)行的地址不確定 關(guān)于...
    SeanCST閱讀 7,813評(píng)論 0 27
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,103評(píng)論 1 32
  • 在Linux下程序不尋常退出時(shí)淌山,內(nèi)核會(huì)在當(dāng)前工作目錄下生成一個(gè)core文件(是一個(gè)內(nèi)存映像裸燎,同時(shí)加上調(diào)試信息)。使...
    隨風(fēng)化作雨閱讀 45,445評(píng)論 2 15
  • 現(xiàn)在化妝的普及已經(jīng)到03后這一代泼疑,可見(jiàn)化妝人群之多德绿。在這個(gè)發(fā)展迅速的時(shí)代里,化妝已經(jīng)是一件正常的不能再正常的事情退渗,...
    guacai4093閱讀 351評(píng)論 0 0