[英]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 EXE
和strace 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.