成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一文讀懂Coredump文件是如何生成的

系統 Linux
在程序發生某些錯誤而導致進程異常退出時,Linux 內核會根據進程當時的內存信息,生成一個 coredump 文件。而 GDB 可以通過這個 coredump 文件重現當時導致進程異常退出的場景,并且可以通過 GDB 來找到導致進程異常退出的原因。

[[415779]]

本文轉載自微信公眾號「Linux內核那些事」,作者songsong001。轉載本文請聯系Linux內核那些事公眾號。

人都會犯錯,所以在編寫程序時難免會出現 BUG。

有些 BUG 是業務邏輯上的錯誤導致的,一般不會導致程序崩潰,例如:原本要將兩個數相加,但不小心把這兩個數相減,而導致結果出錯。這時我們可以通過在程序中,使用 printf 這類輸出函數來進行打點調試。

但有些 BUG 是由于某些致命的操作而導致的,一般會導致程序崩潰,例如:訪問未經申請的內存地址。由于程序會異常退出,所以一般不能通過 printf 這類輸出函數進行打點調試。

另外,對于必現的 BUG (就是不管什么條件都會發生),一般可以通過 GDB 設置斷點進行調試。但對于偶現的 BUG,由于在某些特定的條件下才會發生,所以比較難直接通過 GDB 進行調試。

那么,這時可以通過 Linux 提供的 coredump 文件進行調試。

一、coredump 文件生成過程

在程序發生某些錯誤而導致進程異常退出時,Linux 內核會根據進程當時的內存信息,生成一個 coredump 文件。而 GDB 可以通過這個 coredump 文件重現當時導致進程異常退出的場景,并且可以通過 GDB 來找到導致進程異常退出的原因。

當進程接收到某些 信號 而導致異常退出時,就會生成 coredump 文件。那么,哪些信號會導致生成 coredump 文件呢?

會導致生成 coredump 文件的信號,如下表所示:

Signal Action Comment
SIGQUIT Core Quit from keyboard
SIGILL Core Illegal Instruction
SIGABRT Core Abort signal from abort
SIGSEGV Core Invalid memory reference
SIGTRAP Core Trace/breakpoint trap

下面我們通過一個例子來說明怎么生成 coredump 文件。

從上面的表格可知,當進程接收到 SIGSEGV 信號時會生成 coredump 文件。SIGSEGV 信號是當進程訪問錯誤(未經申請)內存地址時觸發的,所以下面我們編寫一個訪問錯誤內存地址的程序:

  1. int main(int argc, char *argv[]) 
  2.     char *addr = (char *)0; // 設置 addr 變量為內存地址 "0" 
  3.  
  4.     *addr = '\0';           // 向內存地址 "0" 寫入數據 
  5.  
  6.     return 0; 

在上面的例子中,由于內存地址 ”0“ 并沒有通過調用 malloc 函數申請,所以當向地址 ”0“ 寫入數據時將會導致 段錯誤,進程將會接收到 SIGSEGV 信號。

當進程接收到 SIGSEGV 信號后,內核將會根據進程當時的內存信息生成 coredump 文件,并且把進程殺死。

我們將上面的程序編譯并且運行后,會發現程序異常退出,并且生成一個名為 core.xxx 的文件,這個文件就是 coredump 文件。如下圖所示:

注意:

  • 編譯的時候記得加上 -g 參數表示保留調試信息,否則使用 GDB 調試時會找不到函數名或者變量名。
  • 如果沒有生成 coredump 文件的話,一般是受到資源限制,先使用命令 ulimit -c unlimited 設置資源不受限制。

coredump 文件點后面的數字是進程的 PID。

現在我們只需要輸入如下命令,即可使用 GDB 配合 coredump 文件來調試程序了:

  1. $ gdb ./coredump ./core.6359 

GDB 運行后會停止在發生異常的代碼處,并且將發生異常的代碼打印出來,如下圖:

從上面的輸出可以看到,GDB 除了會將發生異常的代碼打印到終端外,還會將其所在的函數、文件名和所在文件的行數也打印出來,這樣我們就很快能定位到哪行代碼導致異常的。

二、coredump文件生成原理

前面介紹過,當進程接收到某些 信號 而導致異常退出時,就會生成 coredump 文件。

當進程從 內核態 返回到 用戶態 前,內核會查看進程的信號隊列中是否有信號沒有處理,如果有就調用 do_signal 內核函數處理信號。我們可以通過下圖來展示內核是怎么生成 coredump 文件的:

進程從內核態返回到用戶態的地方有很多,如 從系統調用返回、從硬中斷處理程序返回 和 從進程調度程序返回 等。上圖主要通過 從進程調度程序返回 作為示例,來展示內核是怎么生成 coredump 文件的。

下面我們來分析一下 coredump 文件生成過程的步驟:

1. 信號處理 do_signal()

當進程從內核態返回到用戶態前,內核會查看進程的信號隊列中是否有信號沒有被處理,如果有就調用 do_signal 內核函數處理信號。我們來看看 do_signal 函數的實現:

  1. static void fastcall do_signal(struct pt_regs *regs) 
  2.     siginfo_t info; 
  3.     int signr; 
  4.     struct k_sigaction ka; 
  5.     sigset_t *oldset; 
  6.  
  7.     ... 
  8.     signr = get_signal_to_deliver(&info, &ka, regs, NULL); 
  9.     ... 

上面代碼去掉了很多與生成 coredump 文件無關的邏輯,最終我們可以看到,do_signal 函數主要調用 get_signal_to_deliver 內核函數來進行進一步的處理。

get_signal_to_deliver 內核函數的主要工作是從進程的信號隊列中獲取一個信號,然后根據信號的類型來進行不同的操作。我們主要關注生成 coredump 文件相關的邏輯,如下代碼:

  1. int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, 
  2.                           struct pt_regs *regs, void *cookie) 
  3.     sigset_t *mask = &current->blocked; 
  4.     int signr = 0; 
  5.  
  6.     ... 
  7.     for (;;) { 
  8.         ... 
  9.         // 1. 從進程信號隊列中獲取一個信號 
  10.         signr = dequeue_signal(current, mask, info);  
  11.  
  12.         ... 
  13.         // 2. 判斷是否會生成 coredump 文件的信號 
  14.         if (sig_kernel_coredump(signr)) { 
  15.             // 3. 調用 do_coredump() 函數生成 coredump 文件 
  16.             do_coredump((long)signr, signr, regs); 
  17.         } 
  18.         ... 
  19.     } 
  20.     ... 

上面代碼去掉了與生成 coredump 文件無關的邏輯,最后我們可以看到 get_signal_to_deliver 函數主要完成三個工作:

調用 dequeue_signal 函數從進程的信號隊列中獲取一個信號。

調用 sig_kernel_coredump 函數判斷信號是否會生成 coredump 文件。

如果信號會生成 coredump 文件,那么就調用 do_coredump 函數生成 coredump 文件。

2. 生成 coredump 文件

如果要處理的信號會觸發生成 coredump 文件,那么內核就會調用 do_coredump 函數來生成 coredump 文件。do_coredump 函數的實現如下:

  1. int do_coredump(long signr, int exit_code, struct pt_regs *regs) 
  2.     char corename[CORENAME_MAX_SIZE + 1]; 
  3.     struct mm_struct *mm = current->mm; 
  4.     struct linux_binfmt *binfmt; 
  5.     struct inode *inode; 
  6.     struct file *file; 
  7.     int retval = 0; 
  8.     int fsuid = current->fsuid; 
  9.     int flag = 0; 
  10.     int ispipe = 0; 
  11.  
  12.     binfmt = current->binfmt; // 當前進程所使用的可執行文件格式(如ELF格式) 
  13.  
  14.     ... 
  15.     // 1. 判斷當前進程可生成的 coredump 文件大小是否受到資源限制 
  16.     if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) 
  17.         goto fail_unlock; 
  18.  
  19.     ... 
  20.     // 2. 生成 coredump 文件名 
  21.     ispipe = format_corename(corename, core_pattern, signr); 
  22.  
  23.     ... 
  24.     // 3. 創建 coredump 文件 
  25.     file = filp_open(corename, O_CREAT|2|O_NOFOLLOW|O_LARGEFILE|flag, 0600); 
  26.  
  27.     ... 
  28.     // 4. 把進程的內存信息寫入到 coredump 文件中 
  29.     retval = binfmt->core_dump(signr, regs, file); 
  30.  
  31. fail_unlock: 
  32.     ... 
  33.     return retval; 

經過代碼精簡后,最終可以看到 do_coredump 函數完成四個工作:

  • 判斷當前進程可生成的 coredump 文件大小是否受到資源限制。
  • 如果不受限制,那么調用 format_corename 函數生成 coredump 文件的文件名。
  • 接著調用 filp_open 函數創建 coredump 文件。
  • 最后根據當前進程所使用的可執行文件格式來選擇相應的填充方法來填充 coredump 文件的內容,對于 ELF文件格式 使用的是 elf_core_dump 方法。

elf_core_dump 方法的主要工作是:把進程的內存信息和內容寫入到 coredump 文件中,并且以 ELF文件格式 作為 coredump 文件的存儲格式。有興趣的可以自行閱讀 elf_core_dump 方法的代碼,這里就不作進一步的解說了。

三、生產環境應該打開 coredump 功能嗎?

最后,我們來討論一下在生產環境應不應該打開 coredump 功能。

筆者遇過在生產環境打開 coredump 功能而導致的事故,故事如下:

我們上線了一個有 BUG 的 WEB 服務,這個程序是以 master-worker 模式運行的。master 進程的主要工作是監控 worker 進程的運行情況,如果 worker 進程掛掉,master 進程會創建新的 worker 進程來繼續工作。

由于 worker 進程的代碼存在漏洞,會導致 worker 進程訪問非法的內存地址而產生 SIGSEGV 信號(段錯誤),而 SIGSEGV 信號會觸發生成 coredump 文件。

由于每次 worker 進程異常退出后,master 進程都會創建新的 worker 進程來補充,所以最終導致 worker 進程不斷的異常退出和被創建。這樣就不斷的生成 coredump 文件,最終導致磁盤被打滿。

所以,經過上面的事故,我建議大家不要在生成環境打開 coredump 功能。那么,如果程序有問題怎么排查呢?

我的建議是摘掉線上的某一臺機器,打開 coredump 功能,然后模擬發生異常的情況來進行排查。如果人工比較難模擬,那么可以通過使用 tcpcopy 這些工具來把線上的流量導入到調試機器進行調試。生成 coredump 文件后,可以使用 GDB 來進行調試。

 

責任編輯:武曉燕 來源: Linux內核那些事
相關推薦

2021-10-18 14:30:55

物聯網IOT

2023-05-11 15:24:12

2023-12-26 14:12:12

人工智能機器學習Gen AI

2023-12-10 14:59:53

2023-12-22 19:59:15

2021-08-04 16:06:45

DataOps智領云

2021-06-07 08:37:03

SQL 查詢語句

2021-08-11 10:21:24

云直播阿里云邊緣云

2022-09-22 09:00:46

CSS單位

2025-04-03 10:56:47

2018-09-28 14:06:25

前端緩存后端

2022-11-06 21:14:02

數據驅動架構數據

2023-04-11 14:48:34

2023-03-08 11:54:00

NB-IoT智能管理

2024-02-29 14:27:37

人工智能機器學習物聯網

2022-08-23 14:56:04

合成數據數據

2019-04-08 09:15:56

2021-09-04 19:04:14

配置LogbackJava

2023-11-21 09:41:00

緩存策略存儲

2022-10-20 08:01:23

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 性高湖久久久久久久久aaaaa | 欧美精品一区三区 | 欧美精品一区二区三区在线 | 婷婷久久一区 | 中文字幕99 | 国产精品一区二区三 | 国产精品视频999 | 一级黄色毛片a | 懂色一区二区三区免费观看 | 日韩免费视频一区二区 | 国产美女一区 | 色一阁 | 成人免费淫片aa视频免费 | 国产精品中文在线 | 人干人操| 五月婷婷丁香婷婷 | 91精品国产91久久久久青草 | 一级毛片免费看 | 一区二区在线 | a欧美 | 激情婷婷成人 | 亚洲一一在线 | 亚洲一区二区久久久 | 久久亚洲春色中文字幕久久久 | a国产视频| 欧美久久国产精品 | 欧美一区二区三区在线观看 | 亚洲欧洲国产视频 | 国产视频一二三区 | 久久成人综合 | 欧美日韩中文国产一区发布 | 91成人在线 | 亚洲综合日韩精品欧美综合区 | 很黄很污的网站 | 国产一区二区精品自拍 | 国产精品国产精品国产专区不卡 | 国产一级在线观看 | 欧美三级久久久 | 亚洲一区欧美 | 在线免费观看日本 | 欧美淫片 |