如何在Docker内部使用gdb调试器
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Docker内部使用gdb调试器相关的知识,希望对你有一定的参考价值。
参考技术A 前几天一个小伙伴发邮件问我,他在docker内部使用gdb调试时刻遇到了gdb如下报错信息
ptrace:Operation not permitted
当时我的答复是在docker create或者docker run时刻开启 万精油--privileged参数 。小伙伴的问题就此解决了。
但是事实并非如此简单
Docker借用了linux对进程设置capabilities,而其子进程继承父进程capabilites特性来完成对容器capacities的控制。Docker create和docker run参数中有下面两个参数可以对容器默认的capabilites进行修改:
--cap-add //添加某个capabilites属性 --cap-del //剔除某个默认的capabilites属性
cap-add和cap-del可以设置的参数可以通过下面链接查询到:
https://docs.docker.com/engine/reference/commandline/run/
但是这并不是问题的全部,对于上述测试程序,如果执行下面命令gdb又有告警出来
虽然依然可以调试,但是我们还是需要搞清楚上述告警的意思。地址随机化是linux一项安全特性,它允许内核进程启动每次加载库的时候都在随机化的分布在进程虚拟内存地址空间上(早期固定的库要加载到固定地方,如果固定地方被占用才加载到别地方。会造成多次加载程序,其库地址都不变。如此有安全隐患)。在gdb调试中gdb默认需要关闭linux的地址随机化功能,可以通过gdb 命令set disable-randomization off关闭。 如果在地址随机化下调试同一段程序,多次run时候可以看到它的运行地址和函数地址不一致,这没有什么太大的问题。问题可以结束一半了
关于gdb 设置地址随机化开关详情见下面链接:
http://visualgdb.com/gdbreference/commands/set_disable-randomization
当然上述告警其实也可以不通过gdb设置来完成,可以通过下面介绍的Docker参数可以达成。
Docker默认情况下为每个容器都设置了一个默认的seccom profile。一般情况下无需修改。但是docker依然支持
docker create或者docker run时候通过--security-opt seccomp=xxx参数来设置docker容器的seccomp策略。
xxx可以是一个json格式文件,里面定义了docker容器每个具体的seccomp规则。也可以是字符unconfined表示关闭默认的docker seccomp 规则。
可以通过下面命令彻底关闭docker默认seccomp引入的任何限制
docker run -it --security-opt seccomp=unconfined centos:lastes
在运行上述gdb 调试命令run一个进程,告警信息终于彻底消失了。
Docker设置的seccomp 默认profile规则可以通过如下链接查询到:
https://docs.docker.com/engine/security/seccomp/
本文就不再做详细展开了。
从Linux 2.6.23开始支持这种特性对进程能够使用的系统调用进行控制,如此可以进行一些安全性策略。sandbox就是依赖于此技术。docker梳理了Linux的系统调用,从300+个系统调用中屏蔽掉了44个系统调用,但是又最大程度的不影响正常的应用使用系统。
从Linux 2.1开始支持的特性,将超级用户的权限划分为多个组,每个进程都有一个capabilities属性,子进程从自己的父进程中基础capacities。这个特性和sudo不一样,因为sudo控制粒度太粗;而capabilities控制粒度很精细。linux有一系列的调用可以设置、查看,清除和比较进程的capabilities。可以通过:
man cap_set_flag
来查看这一系列的系统调用。而具体进程的capacities可以通过/proc/$pid/status中:
Capxxx字段看到,本文就不再展开。感兴趣的朋友可以参考
https://www.cnblogs.com/iamfy/archive/2012/09/20/2694977.html
GDB调试器
---恢复内容开始---
gdb是Linux下一款功能强大的C/C++程序调试器,能够在程序运行的过程中观察程序的内部结构和内存的使用情况。
一般来说,gdb的主要功能有:
1、设置断点(断点可以是条件表达式),使程序在指定的代码行上暂停执行,便于观察;
2、单步执行程序,便于调试;
3、查看程序中变量值的变化;
4、动态改变程序的执行环境;
5、分析崩溃程序产生的core文件。
在gdb后面给出文件名,直接制定想要调试的程序,gdb就会自动调用这个可执行文件进行调试,如:
#gdb filename
注意:为了使gdb正常工作,必须使程序在编译的时候包含调试信息,这需要在gcc编译时加上-g或者-ggdb选项。调试信息包含了程序中每个变量的类型和在可执行文件中的地址映射及源代码的行号。
gdb常用的命令:
File:装入想要调试的可执行文件
run:执行当前被调试的程序
kill:终止正在调试的程序
step:执行一行源代码而且进入函数内部
next:执行一行源代码但不进入函数内部
break:在代码里设置断点,这将使程序执行到这里时被挂起
print:打印表达式或变量的值,或打印内存中某个变量开始的一段连续区域的值,还以用来对变量进行赋值
display:设置自动显示的表达式或变量,当程序停住或在单步跟踪时,这些变量会自动显示其当前值
list:列出产生执行文件的源代码的一部分
quit:退出gdb
watch:使你能监视一个变量的值而不管它何时被改变
backtrace:回溯跟踪
frame n:定位到发生错误的代码段,n为backtrace命令的输出结果中的行号
examine:查看内存地址中的值
jump:使程序跳转执行
signal:产生信号量
return:强制函数返回
call:强制调用函数
make:使用户不退出gdb就可以重新产生可执行文件
shell:使用户不离开gdb就执行Linux的Shell命令
用户可以通过在gdb下输入“help”命令来查看如何使用gdb,或者是在命令提示符下输入“gdb h”来得到一个关于gdb命令选项说明的简单列表。
---恢复内容结束---
以上是关于如何在Docker内部使用gdb调试器的主要内容,如果未能解决你的问题,请参考以下文章