VSCode Docker(Code Server)首次调试C++长时间下载debuginfo问题
VSCode Docker(Code Server)首次调试C++长时间下载debuginfo问题
背景
最近在小服务器上部署了vscode docker(code server)以便多处Continue一些项目,结果每次docker重启后首次调试C++时都会下载很久的debug info。
虽然文件只有15.5M,但无魔法的话可能会下载个十来分钟甚至直接下载失败。主要是还没找到这东西下在了哪里没办法持久化。
经过不断尝试,终于让docker重启后编译C++也不去下载这么个东西了。
1 | |
解决办法
在VsCode默认shell配置环境变量:
1 | |
FBI WARNING
以下内容让ChatGPT总结自我与ChatGPT的对话,有明显不合理之处但未改动。
不合理之处如:
- “自动下载巨大的 debuginfo”,其实15.52M不算巨大,主要是没有魔法的话巨慢。
- “尝试 ~/.gdbinit”部分并非“有时仍会:”,而是一定会“Downloading …”。
- “开始怀疑 Docker 持久化”我没怀疑过这个,因为我直到
~目录都持久化了,是GPT忘了才怀疑的。
GDB / debuginfod / Docker / VSCode C++ Debugging 踩坑复盘(Fedora + code-server)
背景
环境:
- Docker 容器
- Fedora 39
code-server- VSCode C/C++ 扩展 (
cppdbg) - GDB 15.1
- C++ (
g++ -g)
目标:
- 在 Docker 中稳定调试 C++
- 避免每次首次 debug 时自动下载巨大的 debuginfo
- 避免 2h 卡死等待下载
- 理解 debuginfod 到底在干什么
- 理解为什么设置 seemingly 无效
第一阶段:发现问题
最初现象:
启动 VSCode Debug 后:
1 | |
而且:
- 下载非常慢
- 经常卡住
- Docker 重启后还会再次下载
- 只有第一次 debug C++ 会触发
- 其他普通程序不会
于是开始怀疑:
- GDB 配置错误?
- VSCode 插件问题?
- Docker 没持久化?
- debuginfo 装错?
- cache 丢失?
第二阶段:尝试通过 launch.json 禁用 debuginfod
最初配置:
1 | |
期间踩坑:
1. environment 必须是 array
错误尝试:
1 | |
报错:
1 | |
后来确认:
VSCode cppdbg 的 schema 要求:
1 | |
2. env 不支持
尝试:
1 | |
结果:
1 | |
3. 即使配置正确,也没用
即使 launch.json 配置完全正确:
1 | |
仍然会:
1 | |
说明:
- VSCode 确实接受了配置
- 但 debuginfod 仍然生效
后来才发现:
GDB 很可能在 VSCode 注入 environment 前,就已经初始化 debuginfod 了。
第三阶段:尝试通过 GDB 命令关闭
尝试:
1 | |
结果仍然无效。
原因后来才明白:
1 | |
这些行为:
发生在 setupCommands 执行之前。
因此:
1 | |
只是:
从现在开始关闭。
而不是:
阻止启动阶段请求。
第四阶段:尝试 ~/.gdbinit
尝试:
1 | |
写入:
1 | |
结果:
依然不稳定。
有时仍会:
1 | |
后来分析:
GDB 初始化顺序中:
- system gdbinit
- auto-load
- shared library scan
- debuginfod init
- user ~/.gdbinit
顺序可能因 Fedora patch 不同而变化。
因此:
用户 gdbinit 并不一定足够早。
第五阶段:开始怀疑 Docker 持久化
因为观察到:
- 同一个 Docker session 内不会再次下载
- 只有 Docker 重启后才会再次下载
于是怀疑:
1 | |
没有持久化。
第六阶段:定位 debuginfod cache
发现:
1 | |
目录存在。
而且:
1 | |
能看到:
1 | |
里面还有:
1 | |
于是开始推测:
- 这就是下载的 15MB
- Docker 重启后没有复用
第七阶段:错误推理(后来证明)
当时错误地认为:
1 | |
并进一步认为:
1 | |
后来通过实验推翻。
第八阶段:关键实验
做了一个非常重要的实验:
1. 删除 cache
1 | |
2. 再次 debug
结果:
1 | |
3. 检查 cache
结果:
1 | |
大小并没有增加。
第九阶段:终于定位真相
这个实验最终证明:
Downloading 15.52 M并不意味着下载成功。
真正发生的是:
1 | |
因此:
- cache 变大:只是临时文件
- cache 变小:失败后清理
- 并没有真正下载完成
第十阶段:理解 debuginfo 到底是什么
发现:
1 | |
只有:
1 | |
而下载提示却是:
1 | |
于是意识到:
debuginfo 不是运行库本体。
而是:
- DWARF debug symbols
- 行号
- 类型信息
- STL 内部结构
- ABI metadata
本质上类似:
1 | |
第十一阶段:尝试安装本地 debuginfo rpm
尝试:
1 | |
结果:
1 | |
原因:
Fedora 默认没有开启 debuginfo repo。
第十二阶段:手动添加 debuginfo repo
因为使用的是阿里云 Fedora 源:
1 | |
没有 debug repo。
于是手动添加:
1 | |
以及:
1 | |
期间还遇到:
1 | |
因为阿里云 updates debuginfo 不完整。
第十三阶段:发现本地 debuginfo 巨大
执行:
1 | |
结果:
1 | |
总大小:
1 | |
于是发现:
为了一个 15MB runtime symbol
Fedora debuginfo rpm 会拉整个 gcc debuginfo dependency tree。
完全不可接受。
第十四阶段:理解“其实不用 debuginfo”
后来发现:
即使:
1 | |
之后:
- 断点正常
- 单步正常
- 用户变量正常
- 自己代码行号正常
因此终于意识到:
对日常 LeetCode / 普通 C++ debug 来说,libstdc++ debuginfo 根本不是必须。
缺少的只是:
- STL 深层内部解析
- libc 行号
- GCC runtime 深层调试
第十五阶段:最终正确解决方案
最终真正有效的方法:
1 | |
写入:
1 | |
之后:
1 | |
彻底消失。
为什么这个方法 finally 有效?
因为:
1 | |
发生在:
GDB 进程启动之前。
因此:
1 | |
于是:
debuginfod subsystem 从一开始就被禁用了。
而之前的方法:
- launch.json
- setupCommands
- ~/.gdbinit
都发生得太晚。
最终状态
现在系统行为:
1 | |
最终结论(重要)
真正的问题不是:
- Docker
- cache
- HOME
- volume
- VSCode
- GDB bug
而是:
Fedora debuginfod 下载极慢 + 初始化时机早于 VSCode 注入环境变量。
最终推荐配置
~/.zshrc
1 | |
经验总结
1. Downloading xxx MB 不等于下载成功
只是 server 告诉你:
1 | |
2. debuginfo 不是运行库
1 | |
只是 runtime。
真正大的:
1 | |
3. debuginfod 是增强功能,不是必须
没有它:
普通 C++ debug 仍然完全可用。
4. GDB 初始化非常早
很多“关闭 debuginfod”的方法实际上已经晚了。
5. shell environment 才是最稳定层级
1 | |
比:
- launch.json
- gdbinit
- setupCommands
都更底层、更可靠。
最终一句话总结
这次踩坑的本质是:
GDB 在启动早期自动尝试通过 Fedora debuginfod 下载 libstdc++ 的 DWARF 调试符号;由于网络极慢导致长期卡顿,而 VSCode/GDB 层面的关闭方法时机太晚,最终只有在 shell 启动阶段通过
export DEBUGINFOD_URLS=""才真正彻底禁用 debuginfod。
The End
忽然发现Linux上文件排序顺序和Windows上不同,所以Readme文章顺序,,。。。
同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~
千篇源码题解已开源