Optimized code on Unix?

What's the best and easiest way to debug optimized Unix code that is written in C?

Sometimes we also don't have any code to create an unoptimized library.

+2


source to share


3 answers


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 ...

+3


source


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.

+2


source


Write small code samples with the same interfaces (something in its header) and call your samples instead of that optimized code, say simulations, to narrow down the scope of the code you are debugging. Also, you can make mistakes in your samples.

0


source







All Articles