mcpField
D
debug-optimized-builds

debug-optimized-builds

github.com/mohitmishra786开发269544 次安装18 周前更新
代码仓库

关于 debug-optimized-builds

debug-optimized-builds 是帮助 Agent 调试优化后代码的技能,面向使用 GDB 和 GCC、Clang 或 CMake 的开发者。它讲解优化级别、内联栈帧、源码行偏差及 split-DWARF 等问题。

主要功能

  1. 01选择适合调试的优化级别
  2. 02理解“value optimized out”
  3. 03检查 GDB 中的内联栈帧
  4. 04诊断优化代码的行号偏差
  5. 05使用 split-DWARF 加快调试构建

适用场景

  1. 01调试带调试信息的发布构建
  2. 02分析 GDB 中不可见的变量
  3. 03追踪被内联函数的调用栈
  4. 04检查优化代码中的指令与源码映射

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill debug-optimized-builds

安装后在 Claude Code 中输入/debug-optimized-builds确认已加载。

详细介绍

调试优化构建

用途

指导 Agent 调试经过优化编译的代码:选择合适的调试友好型优化级别、查看内联栈帧、诊断“value optimized out”、使用 split-DWARF 加快调试构建,以及应用针对优化代码的 GDB 技巧。

触发条件

  • “GDB 提示 ‘value optimized out’——这是什么意思?”
  • “如何调试发布构建?”
  • “如何在 GDB 中查看内联函数栈帧?”
  • “用于调试时,-O0 和 -Og 有什么区别?”
  • “如何通过 CMake 使用 RelWithDebInfo?”
  • “优化代码中的断点停在了错误的行上”

工作流

1. 选择合适的构建配置
Goal?
├── Full debuggability, no optimization
│   → -O0 -g                        (slowest, all vars visible)
├── Debuggable, some optimization (recommended for most dev work)
│   → -Og -g                        (-Og keeps debug experience good)
├── Release build with debug info (shipped, debuggable crashes)
│   → -O2 -g -gsplit-dwarf          (or -O2 -g1 for lighter info)
└── Full release (no debug symbols)
    → -O2 -DNDEBUG

-Og:GCC 的“调试友好型优化”——启用不会干扰调试的优化。变量会保留在 GDB 可查看的寄存器中。行号保持准确。最适合开发的平衡选择。

# GCC / Clang
gcc -Og -g -Wall main.c -o prog

# CMake build types
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug          # -O0 -g
cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo # -O2 -g -DNDEBUG
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release        # -O2 -DNDEBUG
2. “Value optimized out”——原因和解决方法
(gdb) print my_variable
$1 = <optimized out>

这意味着编译器判定此时无需存储该变量的值——它可能:

  • 仅保留在某个寄存器中(而不是 GDB 正在查看的寄存器)
  • 通过常量传播折叠为常量
  • 因为此后不再使用而被消除
  • 被后续的优化值替代

解决方法:

// 1. Mark variable volatile (prevents optimization away)
volatile int counter = 0;
// Use sparingly — changes semantics

// 2. Use GCC attribute
int counter __attribute__((used)) = 0;

// 3. Compile problematic TU at lower optimization
// In CMake:
set_source_files_properties(tricky.c PROPERTIES COMPILE_FLAGS "-O0")

// 4. Use -Og instead of -O2 for the whole build

// 5. Look at register values directly
// (gdb) info registers
// (gdb) p/x $rax       # value may be in a register
3. 在 GDB 中查看内联栈帧

启用优化后,频繁调用的小函数会被内联。GDB 会将它们显示为额外的栈帧:

(gdb) bt
#0  process_packet (data=0x7ff..., len=<optimized out>)
    at network.c:45
#1  0x0000... in dispatch_handler (pkt=0x7ff...)
    at handler.c:102
#2  (inlined by) event_loop () at main.c:78
#3  0x0000... in main () at main.c:200

# (inlined by) frames are virtual — they show the call chain
# that was inlined into the actual frame above
# Navigate inlined frames
(gdb) frame 2          # jump to the inlined frame
(gdb) up               # move up through frames (including inlined)
(gdb) down             # move down

# Show all frames including inlined
(gdb) backtrace full

# Set breakpoint inside inlined function
(gdb) break network.c:45      # may hit multiple inlined call sites
(gdb) break process_packet    # hits all inline expansions
4. 行号差异

优化器会重新排列指令,因此 GDB 中的“当前行”可能会跳来跳去:

# See which instructions map to which source lines
(gdb) disassemble /s function_name    # interleaved source and asm

# Step by machine instruction (more accurate in optimized code)
(gdb) si        # stepi — one machine instruction
(gdb) ni        # nexti — one machine instruction (no step into)

# Show mixed source/asm at current point
(gdb) layout split   # TUI mode: source + asm side by side
(gdb) set disassemble-next-line on

# Jump to specific address (when line stepping is unreliable)
(gdb) jump *0x400a2c
5. 用于优化多线程代码的 GDB scheduler-locking

启用优化后,单步执行时线程可能会以意料之外的方式发生竞争:

# Lock the scheduler — only the current thread runs while stepping
(gdb) set scheduler-locking on

# Modes:
# off      — all threads run freely (default)
# on       — only current thread runs while stepping
# step     — only current thread runs while single-stepping
#            (all run on continue)
# replay   — for reverse debugging

# Common debugging session
(gdb) set scheduler-locking step    # prevent other threads interfering with step
(gdb) break my_function
(gdb) continue
(gdb) set scheduler-locking on     # lock while examining
(gdb) next
(gdb) set scheduler-locking off    # unlock to continue normally
6. split-DWARF——更快的调试构建

split-DWARF 会将调试信息移至 .dwo 文件,从而减少链接器的输入:

# Compile with split DWARF
gcc -g -gsplit-dwarf -O2 -c file.c -o file.o
# Creates: file.o (object) + file.dwo (DWARF sidecar)

# Link — no debug info in final binary, just references
gcc -g -gsplit-dwarf file.o -o prog

# GDB finds .dwo files via the path embedded in the binary
gdb prog    # works automatically if .dwo files are next to the binary

# Package all .dwo into a single .dwp for distribution
dwp -o prog.dwp prog    # GNU dwp tool
gdb prog    # with .dwp in same directory

# CMake
add_compile_options(-gsplit-dwarf)
7. 用于优化构建的实用 GDB 命令
# Show where variables actually live (register vs stack)
(gdb) info locals           # all locals (may show <optimized out>)
(gdb) info args             # function arguments

# Force evaluation of an expression
(gdb) call (int)my_func(42)  # call actual function to get value

# Watch a memory address directly (not a variable name)
(gdb) watch *0x7fffffffe430

# Print memory contents
(gdb) x/10xw $rsp           # 10 words at stack pointer (hex)
(gdb) x/s 0x4008a0          # string at address

# Catch crashes without debug symbols
(gdb) bt             # backtrace — shows addresses even without symbols
(gdb) info sharedlibrary    # shows loaded libs for symbol resolution

# .gdbinit helpers for optimized debugging
# set print pretty on
# set print array on
# set disassembly-flavor intel

相关技能

  • 使用 skills/debuggers/gdb 管理完整的 GDB 会话
  • 使用 skills/debuggers/dwarf-debug-format 了解 DWARF 调试信息详情
  • 使用 skills/debuggers/core-dumps 对优化构建中的崩溃进行事后调试
  • 使用 skills/compilers/gcc 选择 -Og、-g 和调试标志

评论

支持 Markdown