How to read variables optimized out in GDB?
luajit.io
luajit.io
Sometimes, it's just gone, literally optimized out completely. Consider this piece of code:
bool foo(void) {
int v = some_system_call();
bool b = v > 500;
some_function(b);
... /\* rest of code not using v \*/
}
There is no reason for the original value of v to stick around any longer than until the comparison with 500 has been made.Even though the syntactic scope of "int v" tells you that v is valid for the rest of the function body, and indeed it is while you are writing the source code, an optimizing compiler can and should make use of the fact that you are not actually using it anymore.
-fno-eliminate-unused-debug-symbols
-fno-eliminate-unused-debug-types
https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug.html https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html
this post seems way more hardcore and beyond my experience though.
I haven't looked at DWARF for ages. Can it describe the situation that a variable is valid (in some register) in the beginning of a function, but then goes "out of scope " in the middle of the function?
Yes, with DW_OP_entry_value used in location expressions to indicate that the variable value is in a certain location on entry to the function. However -- debuggers typically don't store all register values on entry to all functions, so usually the stack frame up needs to be instrumented with call site information indicating where the debugger can find longer-term stored copies of the arguments.
In TFA you can see that happening correctly wherever there's a "@entry" annotation from gdb for an argument, in some cases there isn't a longer-term copy of the value further up the stack, in which case the variable remains optimised out.
I'm not talking about "the general case". I'm referring to all the cases where the compiler obviously should know where the value is, yet the debugger somehow doesn't.
Soooommmee of this can be explained by the design decisions in the compiler not lending themselves to working well with debug-info, as explained here [0] (shamless plug), from about 3 minutes in there's an example of a scenario where a variable location has to be discarded out of conservative precaution (4:40 to 7:00), rather than because it's definitely been optimised out.
So this complaint really is about cases related to the optimizer which, as mentioned, is a very complex issue.
0x0000564ab5d178c4 <+52>: callq *%rax
=> 0x0000564ab5d178c6 <+54>: mov %rbp,%rdi
%rsi indeed hasn't been clobbered when the call executes, but it becomes liable to be clobbered during the execution of the callee. By the next instruction (at +54) there's no guarantee that %rsi contains the correct value, thus it's best reported as optimised out. The author is handily stopped at a point in time between the two instructions displayed above (in a lower stack frame), where the correct value happens to be in %rsi, but this is not guaranteed to be always true.In practice, well, things are complicated. Maintaining sane debug information across optimizations is pretty hard, and nobody really holds compiler author’s feet to the fire to make it happen. There’s a lot of low hanging fruit that should be fixed (for example an index→pointer conversion should be easy to undo, even though most compilers don’t generate the debug information for this). Likewise variables that just happen to be alive by chance should be made available. But I doubt we’ll ever get good support for things which have been fully optimized, though I think most programmers will forgive this.
So you can do similar tricks in LLDB, Visual Studio, and many others.
https://github.com/rurban/binutils-gdb/commits/users/rurban/...