gdb
先来个gdb手册链接
这里记录一下自己常用的技巧
恢复debug符号
通常上线的程序要strip符号表来减少内存占用和硬盘占用,会执行以下命令
1 | ## 1. 只保留debug表的内容(可选),为以后调试用,生产时不用 |
如果生产出问题了,就需要恢复debug信息,add-gnu-debuglink参数可以是foo.dbg, 也可以就是strip之前的foo文件
所以第一步是可选的
1 | ## 3. 恢复debug信息 |
但其实第三步也是可选的,只要把foo.dbg放到foo相同位置时,gdb就可以读取到debug信息
使用.gdbinit
.gdbinit 文件是类似.bash_profile的文件,一般在home目录或者项目根目录, gdb 自动读取
也可以手动读取其他位置的, 在gdb执行source /somedir/.gdbinit
通常可以在这个文件里定义一些设置例如set pagination off
关闭输出分页, 就不用每次交互确定
还可以定义命令 如pvector可以打印vector内的所有成员, 非常比较方便
gdb 调试容器内的进程
因为容器内运行的程序都是strip了debug符号的,所以之前调试都是先将debug文件复制到容器对应位置,然后将源码也映射到容器内,而且还要安装gdb和重新开启priveledge模式, 非常繁琐。
所以尝试如下操作:
- 能不能单独一个容器安装gdb和符号和代码文件, 跨容器去调试另一个容器的进程呢?
- 能不能在宿主机上直接调试容器进程呢?
经过一番搜索,没有第一种方案的实践办法,但第二种方案亲测可行!
步骤
- 先启动容器,一般业务主进程的pid为1
- 在容器外面执行
ps aux | grep xxx
,因为在很多情况是多个容器跑同一个程序,所以ps aux
通过参数名来确定进程的pid, 当然最好的方式是通过进程namespace了 - 使用sudo gdb -p pid, 提示缺少
Missing separate debuginfo for target
- 将debug符号文件复制到容器对应容器的目录
- 再次attach,提示缺少源文件
/builds/project/src/aaa.cpp
,这是cmake编译时的目录,需要替换 - 在gdb里执行命令 set substitute-path /builds/ /home/my-home/ # from -> to
- 然后使用l可以查看对应的源代码了
总结
可以直接在宿主机上运行gdb来调试容器进程,并替换代码路径为宿主机的目录。
ps: gdb 启动时默认会读取~/.gdbinit 文件, 但是gdb会提示, 这是由于调试docker需要sudo权限,而我的gdbinit在非root目录
1 | warning: File "/home/h/.gdbinit" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load". |
也就是需要手动执行set auto-load safe-path /
或者将 add-auto-load-safe-path /home/h/.gdbinit
写入/root/.gdbinit