簡體   English   中英

docker 容器中的可執行文件不會從 gdb 遠程調試中注冊斷點

[英]Executable in docker container does not register breakpoints from gdb remote debugging

遠程設置

我需要調試一個復雜的 C++ 程序,該程序安裝在由 Kubernetes 控制的 docker 容器中。 docker 容器還提供了一個 gdbserver 並暴露了容器端口 44444。

主機設置

控制和檢查程序的 gdb 部分設置在另一個 docker 容器中。 這是因為 SUSE 環境僅在此容器中可用,而不在我的 VM Box 中的 Ubuntu 18.04 機器上可用。

本地調試運行良好

在 SUSE docker 容器中本地調試程序效果很好。 程序在指定的斷點處暫停,這些斷點也在遠程調試中指定。 所有斷點都在程序的基本源代碼文件中單獨定義,而不是在任何庫中。

經驗證,遠程docker容器中的可執行文件與宿主容器中的相同; 它已使用調試符號和非優化代碼 (-ggdb -O0) 編譯。

問題

遠程調試程序只需要在主機上定義的斷點處停止。 容器中的程序在后台啟動。 當 gdbserver 附加其 process_id 時,程序將停止,直到在 gdb 主機會話中發出“繼續”並轉發到遠程容器中的 gdbserver。

該程序使用基本的 C++ 類文件和共享程序庫以及共享項目庫進行部署。 它以參數啟動並在作業完成后退出。

當程序啟動時,它讀取配置文件、連接到數據庫、讀取數據庫條目、准備數據並將其格式化為 XML 格式的條目並將它們寫入輸出文件。

HelloWorld 遠程調試測試效果很好

為了驗證通過 gdbserver 端口進行的遠程調試設置和連接是否正常工作,我創建了一個簡單的 HelloWorld C++ 程序並將其復制到同一個遠程 docker 容器中並測試其中的斷點行為。

當HelloWorld程序在容器中運行時,遠程調試測試場景工作成功:

  • 內部容器端口 44444 映射到相同的外部端口 ID 44444:
    $ kubectl port-forward eric-bss-eb-tools-65c4955565-xdqtx 44444:44444
    從 127.0.0.1:44444 -> 44444 轉發
    從 [::1]:44444 轉發 -> 44444

  • 遠程容器中的HelloWorld后台啟動,休眠幾秒
    bash-4.4$ ./HelloWorld &
    [1] 1068

  • gdbserver 附加到 HelloWorld process_id 並等待轉發 gdb 命令
    bash-4.4$ ./gdbserver :44444 --attach 1068 // gdbserver 使用暴露的端口
    隨附的; pid = 1068
    監聽 44444 端口

  • 宿主容器中的gdb以TUI方式在HelloWorld源碼文件夾中啟動
    $ gdb -tui HelloWorld
    從 HelloWorld 讀取符號...完成。
    (gdb) b 13
    0x400b2d 處的斷點 1:文件 HelloWorld.cpp,第 13 行。
    (gdb) b 15
    0x400b37 處的斷點 2:文件 HelloWorld.cpp,第 15 行。

  • gdb 通過本地主機和(外部)端口 ID 44444 連接到 gdbserver
    (gdb) 目標遠程:44444
    (gdb) c
    繼續。

  • 遠程 HelloWorld 在斷點 2 處停止; 可以檢查變量; 可以發出進一步的 gdb 命令,如“next”和“step”; 一切都很聰明

目標程序遠程調試不會在斷點處停止

當容器中的目標 C++ 程序使用相同的場景進行調試時,它不會在定義的斷點處停止:

  • 工作流程與 HelloWorld 測試場景相同,不同之處在於,斷點是gdb 連接到 gdbserver(目標遠程:44444)之后定義的。
    這是按照此答案的第二條評論中的建議完成的:( 遠程 gdb 調試不會在斷點處停止)。

    盡管如此,即使在建立到遠程目標的連接之后定義了斷點,它們仍然會被忽略。

  • 遠程 docker 容器中的程序被 gdbserver 暫停,並在 gdb 發出“繼續”命令時繼續執行,但不會在任何斷點處停止。

  • 我根據其他類似的問題描述嘗試了幾個提示,但仍然忽略斷點。
    例如,使用此處相同請求的回答中建議的硬件斷點:( 遠程 gdb 調試不會在斷點處停止

  • 在我的環境中禁止使用 securityContext: privileged=true 運行遠程 docker 容器,因此無法對此進行測試。 請參閱此處的建議:( 當我從 Docker 容器內運行 gdb 時,它不會遇到任何斷點

在定義的斷點處停止在 docker 容器中進行遠程調試時,我缺少什么?

由於 Ubuntu(版本 >= 10.10)中的安全增強,不允許用戶對不是調試器后代的進程進行 ptrace。
默認情況下,進程 A 無法跟蹤正在運行的進程 B,除非 B 是 A 的直接子進程(或 A 以 root 身份運行)。
始終允許直接調試,例如gdb EXEstrace EXE

可以通過將/proc/sys/kernel/yama/ptrace_scope從 1(=默認)更改為 0(=允許所有進程進行跟蹤)來放松限制。 可以通過以下方式更改安全設置:
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

HelloWorld 遠程調試測試效果很好

HelloWorld 容器中的遠程調試運行良好,這是怎么發生的?
HelloWorld 容器是在 Dockerfile 中使用USER userName創建的,該用戶名與登錄到 Ubuntu 的用戶名相同。
用於部署開發容器(帶有要調試的 C++ 程序)的 Dockerfile 定義了與我的 Ubuntu 登錄中使用的用戶名和組名不同的用戶名和組名。

ptrace 范圍描述的所有學分都屬於以下帖子,請參閱 Eliah Kagan 的第二個答案 - 感謝您的詳盡解釋! - 這里:
https://askubuntu.com/questions/143561/why-wont-strace-gdb-attach-to-a-process-even-though-im-root

目標程序遠程調試不會在斷點處停止

猜測:目標程序fork() s 並執行子進程中的大部分代碼(並且您的gdbserver附加父進程)。

為了驗證這一點,插入一些printf("%s:%d: pid=%d\\n", __FILE__, __LINE__, getpid()); 調用目標程序中的戰略位置。 如果我的猜測是正確的,您應該會看到main()connect_to_database()之間的pid發生了變化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM