Linux中國

使用微軟的 ProcDump 調試 Linux

微軟越來越心儀 Linux 和開源,這並不是什麼秘密。在過去幾年中,該公司穩步地增加了對開源的貢獻,包括將其部分軟體和工具移植到 Linux。2018 年底,微軟宣布將其 Sysinternals 的部分工具以開源的方式移植到 Linux,Linux 版的 ProcDump是其中的第一個。

如果你在 Windows 上從事過調試或故障排除工作,你可能聽說過 Sysinternals,它是一個「瑞士軍刀」工具集,可以幫助系統管理員、開發人員和 IT 安全專家監控和排除 Windows 環境的故障。

Sysinternals 最受歡迎的工具之一是 ProcDump。顧名思義,它用於將正在運行的進程的內存轉儲到磁碟上的一個核心文件中。然後可以用調試器對這個核心文件進行分析,了解轉儲時進程的狀態。因為之前用過 Sysinternals,所以我很想試試 ProcDump 的 Linux 移植版。

開始使用 Linux 上的 ProcDump

要試用 Linux 上的 ProcDump,你需要下載該工具並編譯它。(我使用的是 Red Hat Enterprise Linux,儘管這些步驟在其他 Linux 發行版上應該是一樣的):

$ cat /etc/redhat-release
Red Hat Enterprise Linux release 8.2 (Ootpa)
$
$ uname -r
4.18.0-193.el8.x86_64
$

首先,克隆 Linux 版 ProcDump 的版本庫。

$ git clone https://github.com/microsoft/ProcDump-for-Linux.git
Cloning into 'ProcDump-for-Linux'...
remote: Enumerating objects: 40, done.
remote: Counting objects: 100% (40/40), done.
remote: Compressing objects: 100% (33/33), done.
remote: Total 414 (delta 14), reused 14 (delta 6), pack-reused 374
Receiving objects: 100% (414/414), 335.28 KiB | 265.00 KiB/s, done.
Resolving deltas: 100% (232/232), done.
$
$ cd ProcDump-for-Linux/
$
$ ls
azure-pipelines.yml  CONTRIBUTING.md  docs     INSTALL.md  Makefile    procdump.gif  src
CODE_OF_CONDUCT.md   dist             include  LICENSE     procdump.1  README.md     tests
$

接下來,使用 make 構建程序。它能準確地輸出編譯源文件所需的 GCC 命令行參數。

$ make
rm -rf obj
rm -rf bin
rm -rf /root/ProcDump-for-Linux/pkgbuild
gcc -c -g -o obj/Logging.o src/Logging.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Events.o src/Events.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/ProcDumpConfiguration.o src/ProcDumpConfiguration.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Handle.o src/Handle.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Process.o src/Process.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/Procdump.o src/Procdump.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/TriggerThreadProcs.o src/TriggerThreadProcs.c -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/CoreDumpWriter.o src/CoreDumpWriter.c -Wall -I ./include -pthread -std=gnu99
gcc -o bin/procdump obj/Logging.o obj/Events.o obj/ProcDumpConfiguration.o obj/Handle.o obj/Process.o obj/Procdump.o obj/TriggerThreadProcs.o obj/CoreDumpWriter.o -Wall -I ./include -pthread -std=gnu99
gcc -c -g -o obj/ProcDumpTestApplication.o tests/integration/ProcDumpTestApplication.c -Wall -I ./include -pthread -std=gnu99
gcc -o bin/ProcDumpTestApplication obj/ProcDumpTestApplication.o -Wall -I ./include -pthread -std=gnu99
$

編譯過程中會創建兩個新的目錄。第一個是 obj/ 目錄,存放編譯期間創建的對象文件。第二個(也是更重要的)目錄是 bin/,它是存儲編譯出的 procdump 程序的地方。它還會編譯另一個名為 ProcDumpTestApplication 的測試二進位文件:

$ ls obj/
CoreDumpWriter.o  Handle.o   ProcDumpConfiguration.o  ProcDumpTestApplication.o  TriggerThreadProcs.o
Events.o          Logging.o  Procdump.o               Process.o
$
$
$ ls bin/
procdump  ProcDumpTestApplication
$
$ file bin/procdump
bin/procdump: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=6e8827db64835ea0d1f0941ac3ecff9ee8c06e6b, with debug_info, not stripped
$
$ file bin/ProcDumpTestApplication
bin/ProcDumpTestApplication: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=c8fd86f53c07df142e52518815b2573d1c690e4e, with debug_info, not stripped
$

在此情況下,每次運行 procdump 實用程序時,你都必須移動到 bin/ 文件夾中。要使它在系統中的任何地方都可以使用,運行 make install。這將這個二進位文件複製到通常的 bin/ 目錄中,它是你的 shell $PATH 的一部分:

$ which procdump
/usr/bin/which: no procdump in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin)
$
$ make install
mkdir -p //usr/bin
cp bin/procdump //usr/bin
mkdir -p //usr/share/man/man1
cp procdump.1 //usr/share/man/man1
$
$ which procdump
/usr/bin/procdump
$

安裝時,ProcDump 提供了一個手冊頁,你可以用 man procdump 訪問:

$ man procdump
$

運行 ProcDump

要轉儲一個進程的內存,你需要向 ProcDump 提供它的進程 ID(PID)。你可以使用機器上任何正在運行的程序或守護進程。在這個例子中,我將使用一個永遠循環的小 C 程序。編譯程序並運行它(要退出程序,按 Ctrl+C,如果程序在後台運行,則使用 kill 命令並輸入 PID):

$ cat progxyz.c
#include <stdio.h>

int main() {
        for (;;)
        {
                printf(".");
                sleep(1);
        }
        return 0;
}
$
$ gcc progxyz.c -o progxyz
$
$ ./progxyz &
[1] 350498
$

運行該程序,你可以使用 pgrepps 找到它的 PID。記下 PID:

$ pgrep progxyz
350498
$
$ ps -ef | grep progxyz
root      350498  345445  0 03:29 pts/1    00:00:00 ./progxyz
root      350508  347350  0 03:29 pts/0    00:00:00 grep --color=auto progxyz
$

當測試進程正在運行時,調用 procdump 並提供 PID。下面的輸出表明了該進程的名稱和 PID,並報告它生成了一個核心轉儲文件,並顯示其文件名:

$ procdump -p 350498

ProcDump v1.1.1 - Sysinternals process dump utility
Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license.
Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi
Monitors a process and writes a dump file when the process exceeds the
specified criteria.

Process:                progxyz (350498)
CPU Threshold:          n/a
Commit Threshold:       n/a
Polling interval (ms):  1000
Threshold (s):  10
Number of Dumps:        1

Press Ctrl-C to end monitoring without terminating the process.

[03:30:00 - INFO]: Timed:
[03:30:01 - INFO]: Core dump 0 generated: progxyz_time_2020-06-24_03:30:00.350498
$

列出當前目錄的內容,你應該可以看到新的核心文件。文件名與 procdump 命令顯示的文件名一致,日期、時間、PID 都會附加在文件名上:

$ ls -l progxyz_time_2020-06-24_03:30:00.350498
-rw-r--r--. 1 root root 356848 Jun 24 03:30 progxyz_time_2020-06-24_03:30:00.350498
$
$ file progxyz_time_2020-06-24_03:30:00.350498
progxyz_time_2020-06-24_03:30:00.350498: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from &apos;./progxyz&apos;, real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: &apos;./progxyz&apos;, platform: &apos;x86_64&apos;
$

用 GNU 項目調試器分析核心文件。

要查看是否可以讀取該轉儲文件,調用 GNU 項目調試器gdb)。記得提供測試二進位文件的路徑,這樣你就可以看到堆棧上所有的函數名。在這裡,bt(回溯)表明,當轉儲被採集時,sleep() 函數正在執行:

$ gdb -q ./progxyz ./progxyz_time_2020-06-24_03:30:00.350498
Reading symbols from ./progxyz...(no debugging symbols found)...done.
[New LWP 350498]
Core was generated by `./progxyz&apos;.
#0  0x00007fb6947e9208 in nanosleep () from /lib64/libc.so.6
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64
(gdb) bt
#0  0x00007fb6947e9208 in nanosleep () from /lib64/libc.so.6
#1  0x00007fb6947e913e in sleep () from /lib64/libc.so.6
#2  0x00000000004005f3 in main ()
(gdb)

gcore 怎麼樣?

Linux 用戶會很快指出,Linux 已經有一個叫 gcore 的命令,大多數 Linux 發行版都有這個命令,它的作用和 ProcDump 完全一樣。你說的對。如果你從來沒有使用過它,可以嘗試用 gcore 來轉儲一個進程的核心。再次運行測試程序,然後運行 gcore,並提供 PID 作為參數:

$ ./progxyz &
[1] 350664
$
$
$ pgrep progxyz
350664
$
$
$ gcore 350664
0x00007fefd3be2208 in nanosleep () from /lib64/libc.so.6
Saved corefile core.350664
[Inferior 1 (process 350664) detached]
$

gcore 列印一條消息,說它已將核心文件保存到一個特定的文件中。檢查當前目錄,找到這個核心文件,然後再次使用 gdb 載入它:

$
$ ls -l  core.350664
-rw-r--r--. 1 root root 356848 Jun 24 03:34 core.350664
$
$
$ file core.350664
core.350664: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from &apos;./progxyz&apos;, real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: &apos;./progxyz&apos;, platform: &apos;x86_64&apos;
$
$ gdb -q ./progxyz ./core.350664
Reading symbols from ./progxyz...(no debugging symbols found)...done.
[New LWP 350664]
Core was generated by `./progxyz&apos;.
#0  0x00007fefd3be2208 in nanosleep () from /lib64/libc.so.6
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-101.el8.x86_64
(gdb) bt
#0  0x00007fefd3be2208 in nanosleep () from /lib64/libc.so.6
#1  0x00007fefd3be213e in sleep () from /lib64/libc.so.6
#2  0x00000000004005f3 in main ()
(gdb) q
$

為了使 gcore 可以工作,你需要確保以下設置到位。首先,確保為核心文件設置了 ulimit,如果設置為 0,核心文件將不會被生成。第二,確保 /proc/sys/kernel/core_pattern 有正確的設置來指定核心模式:

$ ulimit -c
unlimited
$

你應該使用 ProcDump 還是 gcore?

有幾種情況下,你可能更喜歡使用 ProcDump 而不是 gcore,ProcDump 有一些內置的功能,在一些情況下可能很有用。

等待測試二進位文件的執行

無論是使用 ProcDump 還是 gcore,測試進程必須被執行並處於運行狀態,這樣才能提供一個 PID 來生成核心文件。但 ProcDump 有一個功能,就是等待特定的二進位文件運行,一旦發現運行的測試二進位文件與給定的名稱相匹配,它就會為該測試二進位文件生成一個核心文件。它可以使用 -w 參數和程序名稱而不是 PID 來啟用。這個功能在測試程序快速退出的情況下很有用。

下面是它的工作原理。在這個例子中,沒有名為 progxyz 的進程在運行:

$ pgrep progxyz
$

-w 參數調用 procdump,讓它保持等待。在另一個終端,調用測試二進位 progxyz

$ procdump -w progxyz

ProcDump v1.1.1 - Sysinternals process dump utility
Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license.
Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi
Monitors a process and writes a dump file when the process exceeds the
specified criteria.

Process:                progxyz (pending)
CPU Threshold:          n/a
Commit Threshold:       n/a
Polling interval (ms):  1000
Threshold (s):  10
Number of Dumps:        1

Press Ctrl-C to end monitoring without terminating the process.

[03:39:23 - INFO]: Waiting for process &apos;progxyz&apos; to launch...

然後,從另一個終端調用測試二進位 progxyz

$ ./progxyz &
[1] 350951
$

ProcDump 立即檢測到該二進位正在運行,並轉儲這個二進位的核心文件:

[03:39:23 - INFO]: Waiting for process &apos;progxyz&apos; to launch...
[03:43:22 - INFO]: Found process with PID 350951
[03:43:22 - INFO]: Timed:
[03:43:23 - INFO]: Core dump 0 generated: progxyz_time_2020-06-24_03:43:22.350951
$

$ ls -l progxyz_time_2020-06-24_03:43:22.350951
-rw-r--r--. 1 root root 356848 Jun 24 03:43 progxyz_time_2020-06-24_03:43:22.350951
$
$ file progxyz_time_2020-06-24_03:43:22.350951
progxyz_time_2020-06-24_03:43:22.350951: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from &apos;./progxyz&apos;, real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: &apos;./progxyz&apos;, platform: &apos;x86_64&apos;
$

多個核心轉儲

另一個重要的 ProcDump 功能是,你可以通過使用命令行參數 -n <count> 指定要生成多少個核心文件。核心轉儲之間的默認時間間隔是 10 秒,但你可以使用 -s <sec> 參數修改。這個例子使用 ProcDump 對測試二進位文件進行了三次核心轉儲:

$ ./progxyz &
[1] 351014
$
$ procdump -n 3 -p 351014

ProcDump v1.1.1 - Sysinternals process dump utility
Copyright (C) 2020 Microsoft Corporation. All rights reserved. Licensed under the MIT license.
Mark Russinovich, Mario Hewardt, John Salem, Javid Habibi
Monitors a process and writes a dump file when the process exceeds the
specified criteria.

Process:                progxyz (351014)
CPU Threshold:          n/a
Commit Threshold:       n/a
Polling interval (ms):  1000
Threshold (s):  10
Number of Dumps:        3

Press Ctrl-C to end monitoring without terminating the process.

[03:45:20 - INFO]: Timed:
[03:45:21 - INFO]: Core dump 0 generated: progxyz_time_2020-06-24_03:45:20.351014
[03:45:31 - INFO]: Timed:
[03:45:32 - INFO]: Core dump 1 generated: progxyz_time_2020-06-24_03:45:31.351014
[03:45:42 - INFO]: Timed:
[03:45:44 - INFO]: Core dump 2 generated: progxyz_time_2020-06-24_03:45:42.351014
$
$ ls -l progxyz_time_2020-06-24_03:45:*
-rw-r--r--. 1 root root 356848 Jun 24 03:45 progxyz_time_2020-06-24_03:45:20.351014
-rw-r--r--. 1 root root 356848 Jun 24 03:45 progxyz_time_2020-06-24_03:45:31.351014
-rw-r--r--. 1 root root 356848 Jun 24 03:45 progxyz_time_2020-06-24_03:45:42.351014
$

基於 CPU 和內存使用情況的核心轉儲

ProcDump 還可以讓你在測試二進位或進程達到一定的 CPU 或內存閾值時觸發核心轉儲。ProcDump 的手冊頁顯示了調用 ProcDump 時使用的命令行參數:

  • -C:當 CPU 超過或等於指定值時,觸發核心轉儲生成(0 到 100 * nCPU)。
  • -c:當 CPU 小於指定值時,觸發核心轉儲生成(0 到 100 * nCPU)。
  • -M:當內存提交超過或等於指定值(MB)時,觸發核心轉儲生成。
  • -m:當內存提交小於指定值(MB)時,觸發核心轉儲生成。
  • -T:當線程數超過或等於指定值時觸發。
  • -F:當文件描述符數量超過或等於指定值時觸發。
  • -I:輪詢頻率,單位為毫秒(默認為 1000)。

例如,當給定 PID 的 CPU 使用率超過 70% 時,可以要求 ProcDump 轉儲核心:

procdump -C 70 -n 3 -p 351014

結論

ProcDump 是一長串被移植到 Linux 的 Windows 程序中的一個有趣的補充。它不僅為 Linux 用戶提供了額外的工具選擇,而且可以讓 Windows 用戶在 Linux 上工作時更有熟悉的感覺。

via: https://opensource.com/article/20/7/procdump-linux

作者:Gaurav Kamathe 選題:lujun9972 譯者:wxy 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國