| name | debug-optimized-builds |
| description | 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. |
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.
gcc -Og -g -Wall main.c -o prog
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
2. "Value optimized out" — causes and workarounds
(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:
volatile int counter = 0;
int counter __attribute__((used)) = 0;
set_source_files_properties(tricky.c PROPERTIES COMPILE_FLAGS "-O0")
3. Reading inlined frames in GDB
With optimization, frequently-called small functions get inlined. GDB shows these as extra frames:
(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
(gdb) frame 2
(gdb) up
(gdb) down
(gdb) backtrace full
(gdb) break network.c:45
(gdb) break process_packet
4. Line number discrepancies
Optimizers reorder instructions, so the "current line" in GDB may jump around:
(gdb) disassemble /s function_name
(gdb) si
(gdb) ni
(gdb) layout split
(gdb) set disassemble-next-line on
(gdb) jump *0x400a2c
5. GDB scheduler-locking for optimized multithreaded code
With optimization, threads may race in unexpected ways when stepping:
(gdb) set scheduler-locking on
(gdb) set scheduler-locking step
(gdb) break my_function
(gdb) continue
(gdb) set scheduler-locking on
(gdb) next
(gdb) set scheduler-locking off
6. split-DWARF — faster debug builds
Split DWARF offloads debug info to .dwo files, reducing linker input:
gcc -g -gsplit-dwarf -O2 -c file.c -o file.o
gcc -g -gsplit-dwarf file.o -o prog
gdb prog
dwp -o prog.dwp prog
gdb prog
add_compile_options(-gsplit-dwarf)
7. Useful GDB commands for optimized builds
(gdb) info locals
(gdb) info args
(gdb) call (int)my_func(42)
(gdb) watch *0x7fffffffe430
(gdb) x/10xw $rsp
(gdb) x/s 0x4008a0
(gdb) bt
(gdb) info sharedlibrary
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