成人免费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-08-11 10:21:24

云直播阿里云邊緣云

2021-06-07 08:37:03

SQL 查詢語句

2018-09-28 14:06:25

前端緩存后端

2022-09-22 09:00:46

CSS單位

2025-04-03 10:56:47

2022-11-06 21:14:02

數據驅動架構數據

2022-08-23 14:56:04

合成數據數據

2023-04-11 14:48:34

2024-02-29 14:27:37

人工智能機器學習物聯網

2023-03-08 11:54:00

NB-IoT智能管理

2021-09-04 19:04:14

配置LogbackJava

2019-04-08 09:15:56

2023-11-27 17:35:48

ComponentWeb外層

2023-05-20 17:58:31

低代碼軟件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕av在线 | 男女久久久 | 7777精品伊人久久精品影视 | 国产精品视频网站 | 国产精品久久在线观看 | 国产精品资源在线 | 天堂av资源| 国产高清精品一区二区三区 | 欧美一区二区综合 | 欧美亚洲国产日韩 | 黄色免费在线观看网站 | 精品久久久久久久久久久久 | 蜜桃av一区二区三区 | 欧美精品久久久 | 国产精品综合视频 | 亚洲网站在线观看 | 欧美一级二级三级视频 | 日日干夜夜操 | 99免费在线视频 | 欧美日韩专区 | 欧美美乳 | 久久国产精品-国产精品 | 99这里只有精品 | 日韩一区二区不卡 | 成人国产免费观看 | 成人激情视频免费在线观看 | 欧美一a一片一级一片 | 五十女人一级毛片 | 欧美日韩不卡 | 国产日韩一区二区三区 | 99在线免费观看视频 | 黄色免费av | 成人综合在线视频 | 久久久www | 久久aⅴ乱码一区二区三区 亚洲欧美综合精品另类天天更新 | 999久久精品 | 欧美色性 | 看真人视频一级毛片 | 国产精品99久久久久久动医院 | 久久精品小视频 | 久久久久无码国产精品一区 |