当我从 Docker 容器中运行 gdb 时,它没有遇到任何断点
Posted
技术标签:
【中文标题】当我从 Docker 容器中运行 gdb 时,它没有遇到任何断点【英文标题】:gdb does not hit any breakpoints when I run it from inside Docker container 【发布时间】:2016-04-23 16:54:37 【问题描述】:问题
如果我从主机编译和运行,我可以设置并到达断点,但如果我从 docker 容器中执行此操作,gdb 不会到达设置的断点。
重现步骤(所有 sn-ps 都已准备好复制粘贴)
创建一个 docker 文件:
cat << EOF > Dockerfile
FROM ubuntu
RUN apt-get update
RUN apt-get install -y build-essential gdb
EOF
构建映像并在其中运行交互式会话:
docker build -t gdb_problem_testing . && docker run --rm -it gdb_problem_testing bash
从容器内部创建小的 main.cpp,编译并运行 gdb:
cat <<EOF > main.cpp && g++ -g main.cpp && gdb -ex 'break 5' -ex 'run' ./a.out
#include <iostream>
int main(int argc, const char *argv[])
std::cout << "hi\n";
return 0;
EOF
观察 gdb 输出:
GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
[Skipped gdb greeting]
Reading symbols from ./a.out...done.
Breakpoint 1 at 0x40078c: file main.cpp, line 5.
1 #include <iostream>
2
3 int main(int argc, const char *argv[])
4
5 std::cout << "hi\n";
6 return 0;
7
Starting program: /a.out
hi
During startup program exited normally.
(gdb)
从输出可以看出断点没有被命中,虽然程序被执行(打印'hi')并成功退出。我想这里最重要的是程序确实运行了,并且消息在启动程序正常退出期间是一种异常行为(根据GDB ignores my breakpoints)
问题
是什么阻止了 gdb 设置断点以及如何解决这个问题?
到目前为止我尝试了什么
按照here 的建议,我尝试在/etc/apparmor.d/docker
中更改一行(我是在主机中完成的):
将profile docker-default flags=(attach_disconnected,mediate_deleted)
替换为profile docker-default flags=(attach_disconnected,mediate_deleted,complain)
。然后运行docker容器,编译,gdb。结果是一样的:During startup program exited normally
。
按照another answer 中的建议,在容器内,我尝试执行strace -f -o syscall.txt gdb ./a.out
,但出现以下错误:
strace: test_ptrace_setoptions_followfork: PTRACE_TRACEME doesn't work: Permission denied
strace: test_ptrace_setoptions_followfork: unexpected exit status 1
但我不明白如何解决这个问题。我尝试以 root 身份启动容器:sudo docker run --rm -it gdb_problem_testing bash
,然后尝试了 strace——这给了我同样的错误。我必须承认我不明白 docker 是如何管理用户权限的,即容器内的 root 拥有哪些用户权限以及它从谁那里继承了这些权限(来自 docker 守护进程?)。由于我能够打断点,所以当我在主机中运行 gdb 时,我怀疑我的问题会归结为用户权限,但我不知道如何解决。
在主机中,我尝试按照 another answer 中的建议执行 echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
。
【问题讨论】:
您的主机操作系统是什么(发行版和内核版本)?我们可以尝试重现错误。您的示例运行良好 - gdb 在第 5 行成功停止 - 在 Ubuntu 15.04 和 14.04.3 x86_64 的香草、完全修补版本上使用 Ubuntu 14.04.2 的 docker 映像。 非常感谢您试一试。它对你有用的事实给了我一个完全不同的观点。我的主机操作系统是 Ubuntu。 $ uname -a Linux LT0377 3.19.0-42-generic #48~14.04.1-Ubuntu SMP Fri Dec 18 10:24:49 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux。我不明白 Docker 映像中的 Ubuntu 版本是什么。如果我在容器内执行 uname -a 操作,我会得到与主机相同的输出。 @MarkPlotnick 你能告诉我你的 Docker 版本是什么吗? 我使用了 Ubuntu 存储库中的 docker 版本。在 14.04.3 和 15.04 上,它都是Docker version 1.6.2, build 7c8fca2
。
docker 存储库中的 ubuntu
映像似乎是 14.04.3;我错了,它是 14.04.2。
【参考方案1】:
2020.01.04 更新:使用 Kevin W Matthews 提供的 answer —— 更好,因为它授予必要的个人功能,而无需提升整个容器。
tldr;使用
docker run --privileged
更长:我有一些problems with gdb in docker---它正在尝试(但失败)禁用address space layout randomization---但仅在docker-machine
上,而不是在我的本机Linux主机上。
当 gdb 未能禁用 ASLR 时,我的所有断点都将被忽略。使用 --privileged
标志解决了我的问题。您的里程可能会有所不同。
【讨论】:
感谢您的回复!不幸的是,我无法再对其进行测试,因为我无法访问此环境。如果其他人发现您的解决方案有帮助,我会接受它作为答案。 这对我有帮助。令人费解的是为什么没有端点被击中,但随后使用 --privileged 运行容器!我现在可以在容器中正确使用 gdb 也帮了我!在 docker 中,可能需要将当前容器提交到一个新镜像中,然后docker rm <container-name/id>
,然后基于新提交的镜像启动一个新容器(使用--privileged
)以重新启动作业。
我今天遇到了这个问题, --privileged 参数解决了它。谢谢。【参考方案2】:
感谢@rubicks 的回答。
如果您不能使用--privileged
选项(例如,您正在使用来自云的容器),您可以从您的程序中打印堆栈跟踪:
How to automatically generate a stacktrace when my gcc C++ program crashes
【讨论】:
【参考方案3】:我没有提升整个容器,而是能够使用该选项
--security-opt seccomp=unconfined
修复地址空间随机化问题。
有些人还建议启用ptrace
功能
--cap-add=SYS_PTRACE
但这似乎对我没有任何影响。
以下是 Docker compose 的相同设置:
security_opt:
- seccomp:unconfined
cap_add:
- SYS_PTRACE
详情取自this Stack Overflow post。
【讨论】:
这个答案比我的好。我正在编辑我的以参考您的。以上是关于当我从 Docker 容器中运行 gdb 时,它没有遇到任何断点的主要内容,如果未能解决你的问题,请参考以下文章