Optimized code on Unix?
This is a very good question. I have had similar difficulties in the past when I had to integrate third party tools inside my application. In my experience, you should have at least meaningful column in associated symbol files. This is just a list of addresses and associated function names. They are usually removed, and you won't get them from binary ... If you have these symbol files, you can load them when you run gdb or after adding them. If not, you are stuck at the assembly level ...
One weird behavior: even if you have your source code, it will go back and forth in places you don't expect (statements can be redirected to improve performance), or variables no longer exist (optimized!), Setting breakpoints in inline functions is meaningless (they are not there, but in the part of the place where they are embedded). So even with source code, watch out for these pitfalls.
I forgot to mention that symbol files usually have a .gdb extension, but it may be different ...
source to share
This question is not like "the best way to mount a passenger car?"
The best way to debug optimized code on UNIX depends on which UNIX you have, what tools you have, and what problem you are trying to debug.
Debugging a crash is malloc
very different from debugging unresolved symbol at runtime
.
For general debugging techniques, I recommend this book .
Several things will make it easier to debug at the assembly level:
- You should be aware of the calling convention for your platform, so that you can tell what values ββare passed and return, where to find the
this
pointer that registers the "caller" and which is "saved", and so on. - You should know your OS conditional calling convention - what the system call looks like, which registers the system call number, first parameter, etc.
- You need a "master" debugger: you know how to find threads, how to stop individual threads, how to set a conditional breakpoint on an individual instruction, one-step, step into or skip function calls, etc.
It often helps to debug a working program and a broken program "in parallel". If version 1.1 works and version 1.2 does not, where do they diverge with respect to a particular API? Run both programs in the debugger, set breakpoints in the same set of functions, run both programs, and observe the differences in which breakpoints hit and what parameters are passed.
source to share