Optimized code debugging

Hi All!

what is best (convenient) option to suppress optimizing out some variable in order to break and observe its value in debug session?

So far I have used to use this controversial practice of assembly injection:

    var _some_var: *@TypeOf(some_var) = &some_var;
    asm volatile ("push {r0-r7}");
    asm volatile ("mov r0, %[addr]"
        :
        : [addr] "r" (&_some_var),
    );
    asm volatile ("pop {r0-r7}");
    asm volatile ("nop");

I’m sure, there have to be a better way…

The mechanisms are:

  1. Atomics
    const _var = @atomicLoad(@TypeOf(some_var), &some_var, .seq_cst);
    
  2. doNotOptimizeAway See: How to use std.mem.doNotOptimizeAway?
  3. volatile Note: Benchmarking isDigit - #17 by andrewrk
3 Likes

thank you, @dimdin !

I tried to utilize atomic approach, but it seems I did it wrong, as soon as _atomic_report looks to be optimized out anyway (first screenshot). It only shows up if the source data (report) is preserved as a symbol in the binary with my recent approach (second screnshot).


Do you mean that the value is not visible in the debugger as local variable?

What editor and what debugger are you using?

yes, I’d like to be able to see some locals in optimized binary. I use emacs + lldb + openocd. It works great with debug binary, when all symbols in place, but llvm optimizer does its job carefully, so it is tricky to make it keep the symbol with ‘fast’ or ‘small’ target.

Try building with the option -fno-strip (Keep debug symbols).
In build.zig executable options is:

const exe = b.addExecutable(.{
    .strip = false,
    ...
});

of course, I use it. The problem is that llvm’s optimizer may not keep local variables, using general registers for vars, so no memory to refer to and no debug info is required/present in the optimized binary. I struggle to keep selected variables to be kept as memory references. If they are references, debug info (symbol name, mapping, etc.) is kept in binary and available during debug session.

std.mem.doNotOptimizeAway(&report); makes the compiler believe the address of report is used and allocates the variable in memory (because a register does not have an address).

2 Likes

it has worked! Thank you, @dimdin !

1 Like