Debug Optimized Builds

mohitmishra786/low-level-dev-skills/skills/debuggers/debug-optimized-builds

作者 mohitmishra786bdc58472fa9f无许可证253 个星标收录于 2026年10月9日更新于 2026年10月9日仓库3个月前更新

Debugging optimized builds skill for diagnosing issues in release code. Use when debugging RelWithDebInfo builds, using -Og for debuggable optimization, working with split-DWARF, applying GDB scheduler-locking, reading inlined frames, or understanding "value optimized out" messages. Activates on queries about debugging optimized code, RelWithDebInfo, -Og, inlined functions in GDB, value optimized out, GDB with -O2, or debugging release builds.

AI 生成的概览

指导调试优化后的 C/C++ 构建:选择适合调试的优化级别、阅读内联栈帧并使用 GDB。

功能
该技能提供诊断优化(发布)构建问题的说明,涵盖 -O0、-Og、RelWithDebInfo 和 split-DWARF 等构建配置选择。它解释“value optimized out”提示的成因与规避方法、如何在 GDB 中阅读内联栈帧和行号偏差,以及调度器锁定、反汇编视图等 GDB 技巧。产出的是指导与命令示例,而非文件或代码。
适用场景
适用于调试以优化方式编译的代码,例如 RelWithDebInfo 或 -O2 构建,或当 GDB 提示“value optimized out”、断点落在意外行时。也适合关于 -Og 与 -O0 对比、内联函数栈帧、split-DWARF 或多线程调试中调度器锁定的问题。
运行要求
不附带脚本,仅为说明文档。按其操作需要 C/C++ 工具链(GCC 或 Clang)、可选的 CMake 和 GDB,以及用于打包 split-DWARF 文件的 dwp 工具。

Debugging Optimized Builds

Purpose

Guide agents through debugging code compiled with optimization: choosing the right debug-friendly optimization level, reading inlined frames, diagnosing "value optimized out", using split-DWARF for faster debug builds, and applying GDB techniques specific to optimized code.

Triggers

  • "GDB says 'value optimized out' — what does that mean?"
  • "How do I debug a release build?"
  • "How do I see inlined function frames in GDB?"
  • "What's the difference between -O0 and -Og for debugging?"
  • "How do I use RelWithDebInfo with CMake?"
  • "Breakpoints in optimized code land on wrong lines"

Workflow

1. Choose the right build configuration

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's "debug-friendly optimization" — enables optimizations that don't interfere with debugging. Variables stay in registers where GDB can see them. Line numbers stay accurate. Best balance for development.

bash
# GCC / Clanggcc -Og -g -Wall main.c -o prog
# CMake build typescmake -S . -B build -DCMAKE_BUILD_TYPE=Debug          # -O0 -gcmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo # -O2 -g -DNDEBUGcmake -S . -B build -DCMAKE_BUILD_TYPE=Release        # -O2 -DNDEBUG

2. "Value optimized out" — causes and workarounds

text
(gdb) print my_variable$1 = <optimized out>

This means the compiler decided the variable's value doesn't need to be stored at this point — it might be:

  • Kept only in a register (not the one GDB is looking at)
  • Folded into a constant by constant propagation
  • Eliminated because it's not used after this point
  • Replaced by a later optimized value

Workarounds:

c
// 1. Mark variable volatile (prevents optimization away)volatile int counter = 0;// Use sparingly — changes semantics
// 2. Use GCC attributeint 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. Reading inlined frames in GDB

With optimization, frequently-called small functions get inlined. GDB shows these as extra frames:

text
(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
bash
# 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. Line number discrepancies

Optimizers reorder instructions, so the "current line" in GDB may jump around:

bash
# 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 for optimized multithreaded code

With optimization, threads may race in unexpected ways when stepping:

bash
# 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 — faster debug builds

Split DWARF offloads debug info to .dwo files, reducing linker input:

bash
# Compile with split DWARFgcc -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 referencesgcc -g -gsplit-dwarf file.o -o prog
# GDB finds .dwo files via the path embedded in the binarygdb prog    # works automatically if .dwo files are next to the binary
# Package all .dwo into a single .dwp for distributiondwp -o prog.dwp prog    # GNU dwp toolgdb prog    # with .dwp in same directory
# CMakeadd_compile_options(-gsplit-dwarf)

7. Useful GDB commands for optimized builds

bash
# 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

Related skills

  • Use skills/debuggers/gdb for full GDB session management
  • Use skills/debuggers/dwarf-debug-format for DWARF debug info details
  • Use skills/debuggers/core-dumps for post-mortem debugging of optimized crashes
  • Use skills/compilers/gcc for -Og, -g, and debug flag selection

来源与署名

来源:mohitmishra786/low-level-dev-skills位于skills/debuggers/debug-optimized-builds提交bdc5847

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架