Skip to content

[DebugInfo] Misleading debug location at O1/2/3/g/s in inlined code #135937

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
Apochens opened this issue Apr 16, 2025 · 4 comments
Open

[DebugInfo] Misleading debug location at O1/2/3/g/s in inlined code #135937

Apochens opened this issue Apr 16, 2025 · 4 comments

Comments

@Apochens
Copy link
Contributor

Apochens commented Apr 16, 2025

Clang version

Ubuntu clang version 21.0.0 (++20250415033808+d0e4af8a88dc-1~exp1~20250415153924.2354)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/lib/llvm-21/bin

LLDB version

lldb version 21.0.0

Bug-triggering program

 1  int printf(const char *, ...);
 2  int a, c;
 3  unsigned b = 5;
 4  int d() {
 5    if (b)
 6      return b;
 7    c = 8;  // Dead code here
 8  }
 9  int main() {
10    d();
11    printf("%X\n", a);
12  }

After the mid-end optimizations, the debug locations are fine: https://godbolt.org/z/f6e1qbdaM.

When debugging, LLDB stops at the dead line:

Process 37755 stopped
* thread #1, name = 'origin', stop reason = step in
    frame #0: 0x0000555555555165 origin`main at origin.proc.c:7:5
   4    int d() {
   5      if (b)
   6        return b;
-> 7      c = 8;
   8    }
   9    int main() {
   10     d();

I suspect that this bug is caused by function inlining. cc @SLTozer @jryans

@llvmbot
Copy link
Member

llvmbot commented Apr 16, 2025

@llvm/issue-subscribers-debuginfo

Author: Shan Huang (Apochens)

Clang version ``` Ubuntu clang version 21.0.0 (++20250415033808+d0e4af8a88dc-1~exp1~20250415153924.2354) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/lib/llvm-21/bin ```

LLDB version

lldb version 21.0.0

Bug-triggering program

 1  int printf(const char *, ...);
 2  int a, c;
 3  unsigned b = 5;
 4  int d() {
 5    if (b)
 6      return b;
 7    c = 8;  // Dead code here
 8  }
 9  int main() {
10    d();
11    printf("%X\n", a);
12  }

Here is the optimized LLVM IR with the misleading debug location: https://godbolt.org/z/f6e1qbdaM.

define dso_local noundef i32 @<!-- -->main() local_unnamed_addr #<!-- -->1 !dbg !36 {
  ...

3:                                                ; preds = %0
  store i32 8, ptr @<!-- -->c, align 4, !dbg !39, !tbaa !30 ; c = 8;
  br label %4, !dbg !40

4:                                                ; preds = %0, %3
  ...
}

!39 = !DILocation(line: 7, column: 5, scope: !25, inlinedAt: !38)

When debugging, LLDB stops at the dead line:

Process 37755 stopped
* thread #<!-- -->1, name = 'origin', stop reason = step in
    frame #<!-- -->0: 0x0000555555555165 origin`main at origin.proc.c:7:5
   4    int d() {
   5      if (b)
   6        return b;
-&gt; 7      c = 8;
   8    }
   9    int main() {
   10     d();

I suspect that this bug is caused by function inlining. cc @SLTozer @jryans

@dwblaikie
Copy link
Collaborator

I think the LLVM IR looks fine here. Seems like it might be down in codegen: https://godbolt.org/z/Ec1MraPMq

       cmp     dword ptr [rip + b], 0
        jne     .LBB1_2
.Ltmp2:
# %bb.1:
        .loc    1 7 5                           # example.c:7:5 @[ example.c:10:3 ]
        mov     dword ptr [rip + c], 8
.Ltmp3:
.LBB1_2:
        push    rax
        .cfi_def_cfa_offset 16
        .loc    1 11 18                         # example.c:11:18
        mov     esi, dword ptr [rip + a]

That push rax is getting a "flow on" location from the previous basic block. We do have some code that's meant to at least give that instruction a line 0 location to avoid these problems, so I'd look at that code for a bug - perhaps the push rax happens at an even lower layer/after that line-zero-at-start-of-block logic.

@Apochens
Copy link
Contributor Author

@dwblaikie Thanks for your correction! Through my investigation, I found that the push rax instruction was inserted by CodeGen pass prologepilog using Target function X86FrameLowering::emitPrologue.

  // Add prologue to the function...
  for (MachineBasicBlock *SaveBlock : SaveBlocks)
    TFI.emitPrologue(MF, *SaveBlock);
# *** IR Dump After Shrink Wrapping analysis (shrink-wrap) ***:
# Machine code for function main: NoPHIs, TracksLiveness, NoVRegs, TiedOpsRewritten, TracksDebugUserValues

...

bb.1.if.end.i:
; predecessors: %bb.0
  successors: %bb.2(0x80000000); %bb.2(100.00%)

  MOV32mi $rip, 1, $noreg, @c, $noreg, 8, debug-location !38 :: (store (s32) into @c, !tbaa !29); main.c:7:5 @[ main.c:10:3 ]

bb.2.d.exit:
; predecessors: %bb.0, %bb.1

  renamable $esi = MOV32rm $rip, 1, $noreg, @a, $noreg, debug-location !40 :: (dereferenceable load (s32) from @a, !tbaa !29); main.c:11:18
  ...

# *** IR Dump After Prologue/Epilogue Insertion & Frame Finalization (prologepilog) ***:
# Machine code for function main: NoPHIs, TracksLiveness, NoVRegs, TiedOpsRewritten, TracksDebugUserValues

...

bb.1.if.end.i:
; predecessors: %bb.0
  successors: %bb.2(0x80000000); %bb.2(100.00%)

  MOV32mi $rip, 1, $noreg, @c, $noreg, 8, debug-location !38 :: (store (s32) into @c, !tbaa !29); main.c:7:5 @[ main.c:10:3 ]

bb.2.d.exit:
; predecessors: %bb.0, %bb.1

+ frame-setup PUSH64r undef $rax, implicit-def $rsp, implicit $rsp
+ frame-setup CFI_INSTRUCTION def_cfa_offset 16
  renamable $esi = MOV32rm $rip, 1, $noreg, @a, $noreg, debug-location !40 :: (dereferenceable load (s32) from @a, !tbaa !29); main.c:11:18
  ...

@dwblaikie
Copy link
Collaborator

Usually prologue/epilog would be fine to have no location info, since you don't usually break/step there (breakpoints on thefunction should break after the prologue) - perhaps some kind of shrink wrapping or other thing is being done to this function & that's not accounted for by the zero-location-at-start-of-basic-block logic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants