custom-allocators
Custom allocator skill for memory allocation strategies. Use when implementing…
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"
$ npx -y skills add mohitmishra786/low-level-dev-skills --skill debug-optimized-builds --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/debug-optimized-buildsContext preview
The summary Claude sees to decide when to auto-load this skill.
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"
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.
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.
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 / 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
(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:
**Workarounds:**
// 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
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# 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
Optimizers reorder instructions, so the "current line" in GDB may jump around:
# 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
With optimization, threads may race in unexpected ways when stepping:
# 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
Split DWARF offloads debug info to `.dwo` files, reducing linker input:
# 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
A curated suite of AI agent skills for systems and low-level programming — C/C++, Rust, Zig, GPU, bare-metal firmware, Linux kernel/driver development, computer architecture, compiler internals, HPC, and more.
Repo: mohitmishra786/low-level-dev-skills
Custom allocator skill for memory allocation strategies. Use when implementing…
NUMA programming skill for multi-socket memory locality. Use when detecting NUMA topology,…
AF_XDP skill for high-performance XDP sockets. Use when creating AF_XDP sockets, configuring…
DPDK skill for userspace packet I/O. Use when initializing EAL, configuring PMD drivers,…
io_uring skill for Linux async I/O. Use when building high-performance servers with liburing,…
Bare-metal ADC and DAC skill. Use when configuring analog sampling, DMA-driven ADC,…