前言:一句話如下使用
gdb [exec_file] [core_file]
# or
gdb -c [core_file] [exec_file]???#-c指定轉儲的core文件gdb -c core.5213?spp_uc_frequent_contact_ol_worker
# 進入后輸入bt查看調用棧
bt? ? ?#顯示所有幀棧
bt 10? #顯示前面10個幀棧(感覺沒啥用)
bt -10 #顯示后面10個幀棧(感覺沒啥用)
bt full? #顯示幀棧以及局部變量
效果如下:
這篇文章主要講GDB和coredump兩個方面。
一、CoreDump
1. coredump簡介
- core,又稱coredump文件,準確來講是Unix/Linux的記錄機制產生的一種保存程序崩潰時現場狀態的記錄性文件。
- 為何需要這種記錄機制?原因很簡單,程序在在正常執行的時候當然是皆大歡喜,但是如果程序出現致命性錯誤難道不要保存一些現場信息已被分析使用嗎!!Unix/Linux也是如此。Unix/Linux將程序工作的當前狀況存儲成一個文件,主要包括程序運行時候的內存狀態、寄存器狀態、堆棧指針、內存管理等現場信息,這就是coredump。可以說表示這種機制也可以表示該機制產生的文件。
- 在程序崩潰的一瞬間,內核會拋出當時該程序進程的內存詳細情況,存儲在core.xxx文件中(xxx為一個數字如core.699)。
- 如果硬要翻譯的話。(core:內存/核心)、(dump:拋出/扔出)。coredump連起來可以直譯為“吐核”。
2. coredump機制的優缺點分析
缺點:伴隨著core進程的內存空間越大,生成core文件(將內存現場狀態寫入磁盤)的時間就越長。
優點:終止是內存、寄存器、各種函數堆棧信息的保留使得開發人員可以進行調試。
注:當然可以設定coredump產生的條件,指定當前回話可以生成的coredump文件大小(后續講到)。
3. coredump文件的存儲路徑及名稱
之所以說這個問題是因為有時候執行程序出現提示Segmentation?fault,但是當前目錄下并沒有coredump文件。此時,記得check下這里。
對于私有化場景 開啟了spp服務的core文件收集但是并沒有看到core文件:
——解決辦法就是在k8s所有母雞全部開啟core文件收集并指定目錄。
(1)查詢core文件位置
執行如下指令:
cat /proc/sys/kernel/core_pattern
默認值是core,表示當前目錄。否則就是在指定目錄下。
(2)更改coredump文件的存儲位置
通過下面的命令可以更改coredump文件的存儲位置,若你希望把core文件生成到/my/coredata目錄下:
echo “/my/coredata”> /proc/sys/kernel/core_pattern
(3)指定內核生成的coredump文件的文件名
通過修改kernel的參數可以指定內核所生成的coredump文件的文件名。例如,使用下面的命令使kernel生成名字為core.filename.pid格式的core dump文件:
echo “/data/coredump/core.%e.%p” >/proc/sys/kernel/core_pattern
這樣配置后,產生的core文件中將帶有崩潰的程序名、以及它的進程ID。上面的%e和%p會被替換成程序文件名以及進程ID。
?
4、產生coredump文件的條件
ps:這個尤其值得注意。因為通常默認的core文件大小都是0.
(1)查詢當前會話能生成的coredump文件的大小——ulimit? -c
? ? ? ??
????????ps:通常段錯誤卻不生成core文件的原因就是因為這個0.
(2)設置當前回話允許生成的coredump文件大小
????????1)ulimit -c unlimited
????????2)ulimit -c [size]
????????注:(1)這里的size單位是block,1block=512byte。
????????????????(2)以上設置都只是對當前會話有效,若想系統均有效,需進行如下設置。
3)在etc/profile中加入一下一行:
ulimit -c unlimited
ps:這個特性可以用于避免過大core文件生成的作用。
5、coredump產生的原因
造成程序coredump的原因有很多,這里總結一些常見情況:
(1)內存訪問越界
? ? ? a) 由于使用錯誤的下標,導致數組訪問越界。
? ? ? b) 搜索字符串時,依靠字符串結束符來判斷字符串是否結束,但是字符串沒有正常的使用結束符。
? ? ? c) 使用strcpy, strcat, sprintf, strcmp,strcasecmp等字符串操作函數,將目標字符串讀/寫爆。應該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函數防止讀寫越界。
(2)多線程程序使用了線程不安全的函數。
應該使用下面這些可重入的函數,它們很容易被用錯:
asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n)ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c)getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c)fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c)getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_r(3m) getauclassent_r(3)getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n)nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3)getpwent_r(3c) readdir_r(3c) getauevnum_r(3) getpwnam_r(3c) strtok_r(3c) getgrent_r(3c)getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c)getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n)
(3)多線程讀寫的數據未加鎖保護。
對于會被多個線程同時訪問的全局數據,應該注意加鎖保護,否則很容易造成coredump
(4)非法指針
? ? ? a) 使用空指針
? ? ? b) 隨意使用指針轉換。一個指向一段內存的指針,除非確定這段內存原先就分配為某種結構或類型,或者這種結構或類型的數 組,否則不要將它轉換為這種結構或類型的指針,而應該將這段內存拷貝到一個這種結構或類型中,再訪問這個結構或類型。這是因為如果這段內存的開始地址不是按照這種結構或類型對齊的,那么訪問它時就很容易因為bus error而core dump。
(5)堆棧溢出
不要使用大的局部變量(因為局部變量都分配在棧上),這樣容易造成堆棧溢出,破壞系統的棧和堆結構,導致出現莫名其妙的錯誤。
?
6、如何判斷一個文件是core文件
readelf -h 讀取coredump文件頭。如下圖所示:
二、GDB+coredump
1、使用GDB,需要先從執行文件中讀取符號表信息,然后再讀取core文件。即
gdb? test? core.2919
原因:core文件中沒有符號表信息,無法進行調試。驗證如下:objdump -x core.2919 | tail
2、調試過程如下(和使用gdb調試其他程序幾乎一樣):
從上面可以看出出問題的是第十三行。
當然進入GDB之后也可以直接執行where可以立馬找出出錯的位置。如下所示:
/*************************************************************************> File Name: test.cpp> Author: ma6174> Mail: ma6174@163.com > Created Time: 2018年12月24日 星期一 19時10分39秒************************************************************************/#include<stdio.h>int main(){int b=1;int *a=NULL;*a=b;return 0;
}
三、演示gdb調試coredump
(1)源程序如下
#include<stdio.h>
void do_it();
int main(){do_it();return 0;
}
void do_it(){//定義一個字符指針變量a,指向地址1.這個地址肯定不是自己可以訪問的,但是這行不會產生段錯誤。char* p=1;//視圖更改地址1出的值,內核會終止該進程,并把core文件dump出來。*p='a';
}
(2)必要的準備
????????1)確定core文件的生成位置,免得待會兒找不到。(此處采用默認的當前位置)
????????2)設置產生條件 ulimit -c unlimited ,免得一直段錯誤,就是不吐核。
????????3)記住編譯時要加-g選項,gcc -g -o test1 test1.c
(3)運行test1程序 如下
????????
????????說明core已經被dump了,查看對于的core文件是core.3177。
????????
?????????注:每一次執行./test1都會生成一個core.xxx文件,他們的記錄的信息應該都是一樣的。
(4)開始調試
????????調試過程非常簡單:gdb test1 core.3177。進入后運行where即可列出出錯的位置了。
????????
參考:
GDB定位coredump_gdb coredump-CSDN博客