前言
在現網環境下,程式奔潰后不一定會留下core檔案,原因有很多,比如存盤空間不足就是其中一個常見的原因,此時我們只能依據linux記錄的錯誤日志來定位問題,
涉及linux命令
本文涉及以下幾條命令
1. dmesg命令,用于獲取程式出錯時的堆疊地址
1)dmesg |grep -E 'segfault|general'
可以通過該命令過濾出發生崩潰的程式,以及對應的堆疊資訊,之前看網上的其他文章僅過濾segfault,但我在實踐中發現"general protection"的提示資訊也在告訴我們行程崩了,目前我只遇到segfault和general這兩種情況,如果還有其他的過濾條件可以給我留言,
舉例:
[root@vmware ~] dmesg |grep -E 'segfault|general'
[ 374.549753] a.out[57228]: segfault at 0 ip 00000000004004fd sp 00007ffe7296f610 error 6 in a.out[400000+1000]
[ 429.110096] b.out[96783]: segfault at 0 ip 00000000004004fd sp 00007ffcc3e697c0 error 6 in b.out[400000+1000]
欄位說明:
1)ip:指令指標暫存器,欄位后面的數字就是test程式出錯時程式執行的位置
2)sp:堆疊指標暫存器
3)error:錯誤碼,由三個字位組成的,從高到底分別為bit2 bit1和bit0
bit2: 值為1表示是用戶態程式記憶體訪問越界,值為0表示是內核態程式記憶體訪問越界
bit1: 值為1表示是寫操作導致記憶體訪問越界,值為0表示是讀操作導致記憶體訪問越界
bit0: 值為1表示沒有足夠的權限訪問非法地址的內容,值為0表示訪問的非法地址根本沒有對應的頁面,也就是無效地址
4)b.out后面緊跟著的地址(這里是400000)這個在定位時也有用到,不知道該怎么描述,知道的給我留言2)dmesg |grep 進(線)程名
通過行程或執行緒名來過濾,這里之所以強調執行緒,因為我在實踐中發現dmesg里的資訊可能只有執行緒名,所以推薦在給執行緒取名時使用統一前綴,比如你的主行程為Test,那么執行緒可以取Test_A,Test_A,這樣過濾時 grep Test就能過濾出所有想要的資訊
舉例:
[root@vmware ~] dmesg |grep a.out
[ 374.549753] a.out[57228]: segfault at 0 ip 00000000004004fd sp 00007ffe7296f610 error 6 in a.out[400000+1000]3)dmesg -C
dmesg命令查看到的資訊在重啟后將會被清空,若當前錯誤資訊太多也可以通過該命令手動清空dmesg資訊,以便下次問題的定位,-C(大寫)引數為靜默清空,如果清空前還想列印一次,可以通過-c(小寫)引數,
注:
cat /var/log/messages |grep xxx
這里也保存行程奔潰資訊,且重啟后依然存在,
舉例:
[root@vmware ~] cat /var/log/messages|grep b.out
May 8 09:24:04 vmware kernel: b.out[96783]: segfault at 0 ip 00000000004004fd sp 00007ffcc3e697c0 error 6 in b.out[400000+1000]
May 8 09:24:04 vmware abrt-hook-ccpp: Process 96783 (b.out) of user 0 killed by SIGSEGV - dumping core
May 8 09:24:05 vmware abrt-server: Executable '/root/b.out' doesn't belong to any package and ProcessUnpackaged is set to 'no'
2. date 用于轉換dmesg資訊里的時間戳
date -d "1970-01-01 UTC `echo "$(date +%s)-$(cat /proc/uptime|cut -f 1 -d' ')+時間戳"|bc `seconds"
舉例:
[ 672.091250] a.out[26520]: segfault at 0 ip 00000000004004fd sp 00007ffe51b27fe0 error 6 in a.out[400000+1000]
[root@vmware ~] date -d "1970-01-01 UTC `echo "$(date +%s)-$(cat /proc/uptime|cut -f 1 -d' ')+672.091250"|bc `seconds"
2019年 05月 08日 星期三 09:40:02 CST
3. ldd 用于獲取行程所依賴的動態庫,以及所在位置
4. addr2line,將dmesg獲取到的地址轉換為代碼中發成錯誤的檔案、行號及函式名
奔潰發生的位置不同,該命令的使用方式也有所不同
1)在主行程中奔潰
addr2line -e 行程名 IP指令地址 -f
舉例:
#include <stdio.h>
int main()
{
int *p = NULL;
*p = 0;
return 0;
}
[root@vmware ~] gcc a.c -g
[root@vmware ~] ./a.out
段錯誤(吐核)
[root@vmware ~] dmesg |grep a.out
[ 1310.167335] a.out[122089]: segfault at 0 ip 00000000004004fd sp 00007ffcf08f3ab0 error 6 in a.out[400000+1000]
[root@vmware ~] addr2line -e a.out 00000000004004fd -f
func
/root/a.c:5通過該例子我們可以看到,程式發生段錯誤的函式以及具體位置,需要注意的是如果編譯程式時沒有加上-g引數,就只能顯示出函式名,顯示不出具體所在檔案的位置.
2)動態庫中奔潰
addr2line -e 行程名 “IP指令地址-動態庫后緊跟著的地址” -f
舉例:
#include<stdio.h> #include<string.h> void func() { int *p = NULL; memcpy(p, "test", 4); } int main() { func(); return 0; }
[root@vmware ~] dmesg |grep a.out
[ 6807.501481] a.out[72684]: segfault at 0 ip 00007f6559bc7463 sp 00007fff80625b18 error 6 in libc-2.17.so[7f6559a7c000+1b6000]
[root@vmware ~] ldd a.out
linux-vdso.so.1 => (0x00007ffc643f6000)
libc.so.6 => /lib64/libc.so.6 (0x00007f83ef206000)
/lib64/ld-linux-x86-64.so.2 (0x00007f83ef5e2000)[root@vmware ~] addr2line -e /lib64/libc.so.6 14B463 -f
__memcpy_ssse3_back
:?
這個這個例子我們可以看到,段錯誤發生的位置是在a.out行程呼叫的libc庫里,因此addr2line指向的地址使用14B463 = 00007f6559bc7463 - 7f6559a7c000
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/30678.html
標籤:C
