Problem with x86 32-bit debug information ?

Hi all,

I’m using trunk version of LLVM/CLANG.
When I compile attached files on my 64-bit Ubuntu 10.04 LTS system as follows:

clang -O2 -g check.c main.c -o check64

When I do gdb check64 and set a breakpoint to the check routine and executes to the breakpoint, I’ve got:

Breakpoint 1, check (result=0x601110, expect=0x601020, n=53) at check.c:7
7 {

As you can see I can inspect ‘n’ value.

Now if I compile for x86 32-bit as follows:

clang -m32 -O2 -g check.c main.c -o check32

When I do gdb check32 and set a breakpoint to the check routine and executes to the breakpoint, I’ve got:

Breakpoint 1, check (result=,
expect=, n=0) at check.c:7
7 {

As you can see I can NOT inspect ‘n’ value. Is there a way to inforce even at -O2 clang to generate debug informations so that I can inspect ‘n’ value ?
Or is it a BUG from clang for x86 32-bit ?
Thanks for your answers.
Best Regards
Seb

check.c (724 Bytes)

main.c (899 Bytes)

Hi Seb,

Clang cannot generate debug information for something that it has optimised away. You should reduce the optimisation level.

In general debug information is only really accurate at –O0.

Cheers,

James

Hi James,

clang is able to generate correct debug informations for 64-bit target at -O2. My feeling, given some other experiments I’ve done, is that debug information generated for x86 32-bit might be broken for parameters as long as they are not ‘homed’ in the code (local copy to an automatic variable). It seems that when llvm.declare is turned into a llvm.value for parameter there is something incorrect with respect to parameters debug informations that is generated by clang/llvm. I just would like confirmation of this.

Thanks for your answer
Best Regards
Seb

2012/3/7 James Molloy <james.molloy@arm.com>

Hi Seb,

I’m going to reiterate – Clang can decide when it wants to optimise away a variable. You asked for that behaviour when you specified –O2. You can’t expect deterministically the same behaviour on both x86 and x86-64 platforms – the procedure call standards are different and different decisions go in to deciding how to optimise.

You can’t expect debug information for an optimised build to fully track that of the source because by definition the source is being modified to optimise.

Cheers,

James

Hi James,

I fully agree with you and understand your statement about -O2.

Now some questions for you:
Did you try to reproduce experiments described in my previous e-mail ?
Did you look at debug informations generated for ‘n’ parameter on x86 32-bit & x86 64-bit ?
I’m working on my own front-end for LLVM and I had difficulties with debug information when they are related to x86 32-bits. So far there are two options:

  1. metadata that I generate are incorrect.
  2. LLVM is not handling in a correct manner those metadata for x86 32-bit target.
    I’ve already posted problem related to metadata that I generate and they are in LLVM 2.9 format. I’ve been adviced to move to most recent format. Before starting any move into that direction, I would like to be sure that LLVM trunk could solve the problem. Using clang at -O2 -g is giving me some indication that it won’t solve my problem and that we are failing into option (2).
    So to summarize, I would be nice if someone can confirm that debug informations generated on this specific case are correct for x86 32-bit and that I would have to deal with that.

Thanks
Best Regards
Seb

2012/3/7 James Molloy <james.molloy@arm.com>

I do have to take exception to James Molloy's assessment of the variable "n"
as "optimized away" because the debug info clearly thought it wasn't. (The
"n=0" shows that the debug info described some kind of location; if "n" was
indeed optimized away, it should have said so. Either the debug info does
have a bug--giving a location for a nonexistent variable--or something else is
interfering with our expectations.)

It is very easy for people to dismiss problems with optimized-code debugging
with a "well, what did you expect??" kind of attitude. Actually there are three
broad categories that can apply to any such issue.

(a) The compiler is trying to keep the debug info in sync with the generated
code, but got it wrong. This is a correctness bug.
(b) The compiler isn't bothering to keep the debug info in sync with the
generated code, even though it reasonably could do so. This is a
quality-of-implementation issue.
(c) Optimization has made the situation too complicated for the debug info to
reasonably keep track of things. This happens.

There is some slop between the categories, because there are judgement
calls involved in whether something is bad enough to be a bug or is more of
a heuristic that isn't as good as we'd like; equally, there are judgement calls
in what's a "reasonable" degree of effort to keep track of complicated cases.

Blithely tossing every problem into the third category is
inappropriate. I spent
nontrivial time (on a previous compiler project) tracking down optimized-code
debugging issues, and probably half of the time I could do something easy to
address it. Sometimes the compiler was attaching the wrong source location
(bug), sometimes it wasn't bothering to keep track at all even though
it would be
easy (quality of implementation). In a few cases, generating accurate debug
info required extra analysis, and once or twice we went to that extra trouble;
the rest of the time, it didn't seem worthwhile (judgement calls).

Getting down to the specifics of this case, I downloaded the example programs
and tried them as described. I got the same behavior as Seb described.

As for our friend "n=0", after I hit the breakpoint I tried stepping
once. At that
point, "print n" showed "53" just as we would want. While it would be ideal to
see "n=53" at the breakpoint, sometimes debug info and function prologs don't
line up exactly, and stepping sometimes causes things to become more sensible.

So, I think the 32-bit debug info is doing something reasonable, if not exactly
what you would want.

Pogo

Hi,

I do have to take exception to James Molloy's assessment of the variable

"n"

as "optimized away" because the debug info clearly thought it wasn't.

Mea culpa here, I misread the original email and saw "<value optimized out>"
for the wrong parameter. Then didn't recheck the original email when
follow-ups happened.

I apologise.

Cheers,

James

Hi Pogo & James,

Pogo, that is exactly the kind of answer I was expecting. Thanks for the time you spend on this problem. I myself did also some experimenst and found way to get what I’m expecting but I think that at least for x86 or any parameter passed on the stack for a different architecture the way LLVM handle debug information might be a problem. So here was the situation:
My front-end at -O0 generates direct access to parameters and I used llvm.dbg.value to associate metadata and I couldn’t get llc to generate fp related debug info that would have made ‘n’ value available at first breakpoint.
I eventually found looking at what’s generated by clang at -O0 that I should first ‘home’ the parameter (make a local copy to a variable) then use llc -disable-fp-elim so that ‘n’ value can be inspected. My feeling is that LLVM debug info generation is based on LLVM code-style emitted by clang and might not deal when code is emitted by a different front-end.
James, no need to apology we all make mistakes, including myself.

Best Regards
Seb

2012/3/9 James Molloy <james.molloy@arm.com>