[llvm] [DebugInfo] Don't set prologue_end behind line-zero call insts (PR #156850)

Stephen Tozer via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 4 09:13:47 PDT 2025


================
@@ -0,0 +1,129 @@
+# RUN: llc %s -start-after=livedebugvalues -o - -filetype=obj | llvm-dwarfdump - --debug-line | FileCheck %s --implicit-check-not=prologue_end
+#
+## Original code, compiled clang -O2 -g -c
+## 
+## void ext();
+## int main(int argc, char **argv) {
+##   if (argc == 1)
+##     ext();
+##   else
+##     ext();
+##    return 0;
+## }
+## 
+## In the code sequence above, the call to ext is given line zero during
+## optimisation, because the code is duplicated down all function paths thus
+## gets merged. We get something like this as the output:
+##
+##   0:   50                      push   %rax
+##   1:   31 c0                   xor    %eax,%eax
+##   3:   e8 00 00 00 00          call   8 <main+0x8>
+##                        4: R_X86_64_PLT32       ext-0x4
+##   8:   31 c0                   xor    %eax,%eax
+##   a:   59                      pop    %rcx
+##   b:   c3                      ret
+##
+## Where prologue_end is placed on address 8, the clearing of the return
+## register, because it's the first "real" instruction that isn't line zero.
+## This then causes debuggers to skip over the call instruction when entering
+## the function, which is catastrophic.
+##
+## Instead: we shouldn't put a prologue_end on this function at all. It's too
+## deformed from the original code to truly have a position (with a line number)
+## that is both true, and after frame setup. This gives comsumers the
+## opportunity to recognise "this is a crazy function" and act accordingly.
+##
+## Check lines ensure that there's something meaningful in the line table
+## involving line 2, the implicit-check-not is making sure there isn't a
+## prologue_end flag on any line entry.
+#
+# CHECK: standard_opcode_lengths[DW_LNS_set_prologue_end] = 0
+#
+# CHECK:  Address            Line   Column File
+# CHECK:  2      0      0 
+# CHECK:  end_sequence
+--- |
+  ; ModuleID = '/tmp/test.c'
+  source_filename = "/tmp/test.c"
+  target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+  target triple = "x86_64-unknown-linux-gnu"
+  
+  ; Function Attrs: nounwind uwtable
+  define dso_local noundef i32 @main(i32 noundef %argc, ptr noundef readnone captures(none) %argv) local_unnamed_addr !dbg !10 {
+  entry:
+      #dbg_value(i32 %argc, !19, !DIExpression(), !21)
+      #dbg_value(ptr %argv, !20, !DIExpression(), !21)
+    tail call void (...) @ext(), !dbg !22
+    ret i32 0, !dbg !24
+  }
+  
+  declare !dbg !25 void @ext(...) local_unnamed_addr
+  
+  !llvm.dbg.cu = !{!0}
+  !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+  !llvm.ident = !{!9}
+  
+  !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 22.0.0git (/fast/fs/llvm4 8989ec5439dc2df2aeb7e5ea3e6c255ce8e9634d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
----------------
SLTozer wrote:

Can clean up the test strings a bit, removing git hashes and checksums.

https://github.com/llvm/llvm-project/pull/156850


More information about the llvm-commits mailing list