Bug 95574 - line table entry in sequence with address after sequence
Summary: line table entry in sequence with address after sequence
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 11.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-debug
Depends on:
Blocks:
 
Reported: 2020-06-08 09:18 UTC by Tom de Vries
Modified: 2020-07-07 14:13 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
_absvsi2_s.c (39.70 KB, text/plain)
2020-06-08 09:35 UTC, Tom de Vries
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2020-06-08 09:18:05 UTC
When doing a build from current trunk, I get the following in the .debug_line section of build/x86_64-pc-linux-gnu/libgcc/libgcc_s.so.1:
...
  [0x000006f5]  Special opcode 75: advance Address by 5 to 0x2faa and Line by 0 to 246
  [0x000006f6]  Advance PC by 0 to 0x2faa
  [0x000006f8]  Extended opcode 1: End of Sequence
...

This is nonsensical dwarf: both the special opcode and the End-Of-Sequence declare a row in the matrix, each with the same address.

The special opcode declares a target instruction at that address.

The End-of-Sequence declares that the sequence ends before that address.

It's a contradiction that the target instruction is both part of the sequence (according to Copy) and not part of the sequence (according to End-of-Sequence).

[ Relevant dwarf standard bits:

end_sequence:

A boolean indicating that the current address is that of the first byte
after the end of a sequence of target machine instructions. end_sequence
terminates a sequence of lines; therefore other information in the same
row is not meaningful.

Special Opcodes

Each ubyte special opcode has the following effect on the state machine:
1. Add a signed integer to the line register.
2. Modify the operation pointer by incrementing the address and op_index
registers as described below.
3. Append a row to the matrix using the current values of the state machine
registers.

DW_LNE_end_sequence:

The DW_LNE_end_sequence opcode takes no operands. It sets the
end_sequence register of the state machine to “true” and appends a row
to the matrix using the current values of the state-machine registers.
Then it resets the registers to the initial values specified above (see
Section 6.2.2). Every line number program sequence must end with a
DW_LNE_end_sequence instruction which creates a row whose address is
that of the byte after the last target machine instruction of the sequence.

]
Comment 1 Tom de Vries 2020-06-08 09:27:01 UTC
I can track this down to build/x86_64-pc-linux-gnu/libgcc/_absvsi2_s.o
...
  [0x00000116]  Special opcode 75: advance Address by 5 to 0xa and Line by 0 to 246
  [0x00000117]  Advance PC by 0 to 0xa
  [0x00000119]  Extended opcode 1: End of Sequence
...
and using -save-temps I get the corresponding .s file:
...
        .section        .text.unlikely
        .cfi_startproc
        .type   __absvsi2.cold, @function
__absvsi2.cold:
.LFSB26:
.L12:
        .cfi_def_cfa_offset 16
        .loc 1 246 5 is_stmt 1 view .LVU17
        call    abort@PLT
.LVL7:
        .loc 1 246 5 is_stmt 0 view .LVU33
        .cfi_endproc
.LFE26:
...

I think this is due to the last .loc.  I'm not sure if it makes sense to declare a .loc after a non-returning insn.
Comment 2 Tom de Vries 2020-06-08 09:35:01 UTC
Created attachment 48702 [details]
_absvsi2_s.c

To reproduce:
...
$ gcc -O2 -g -fpic -mlong-double-80 -fcf-protection -mshstk -fbuilding-libgcc -fno-stack-protector -o _absvsi2_s.o -c _absvsi2_s.c -save-temps
...
Comment 3 Tom de Vries 2020-06-08 09:36:43 UTC
Gdb currently silently ignores the offending entry.

I've filed a gdb PR, PR26092 - "Complain about contradictory DW_LNE_end_sequence marker" to complain about this ( https://sourceware.org/bugzilla/show_bug.cgi?id=26092 ).
Comment 4 Tom de Vries 2020-07-07 13:40:04 UTC
(In reply to Tom de Vries from comment #2)
> Created attachment 48702 [details]
> _absvsi2_s.c
> 
> To reproduce:
> ...
> $ gcc -O2 -g -fpic -mlong-double-80 -fcf-protection -mshstk
> -fbuilding-libgcc -fno-stack-protector -o _absvsi2_s.o -c _absvsi2_s.c
> -save-temps
> ...

Minimal example test.c:
...
#include <stdlib.h>

int
foo (int a)
{
  int w = a;

  if (a < 0)
    w = -(unsigned int) a;

  if (w < 0)
    abort ();

   return w;
}
...

Compiled like this:
...
$ gcc test.c -O2 -g -c -fno-reorder-blocks-and-partition
...

resulting in test.s:
...
        .file   "test.c"
        .text
.Ltext0:
        .p2align 4
        .globl  foo
        .type   foo, @function
foo:
.LVL0:
.LFB13:
        .file 1 "test.c"
        .loc 1 5 1 view -0
        .cfi_startproc
        .loc 1 6 3 view .LVU1
        .loc 1 8 3 view .LVU2
        .loc 1 5 1 is_stmt 0 view .LVU3
        movl    %edi, %eax
        .loc 1 8 6 view .LVU4
        testl   %edi, %edi
        js      .L7
.LVL1:
.L2:
        .loc 1 14 4 is_stmt 1 view .LVU5
        .loc 1 15 1 is_stmt 0 view .LVU6
        ret
.LVL2:
        .p2align 4,,10
        .p2align 3
.L7:
        .loc 1 9 5 is_stmt 1 view .LVU7
        .loc 1 9 9 is_stmt 0 view .LVU8
        negl    %eax
.LVL3:
        .loc 1 11 3 is_stmt 1 view .LVU9
        .loc 1 11 6 is_stmt 0 view .LVU10
        testl   %eax, %eax
        jns     .L2
        .loc 1 12 5 is_stmt 1 view .LVU11
.LVL4:
        .loc 1 5 1 is_stmt 0 view .LVU12
        pushq   %rax
        .cfi_def_cfa_offset 16
        .loc 1 12 5 view .LVU13
        call    abort
.LVL5:
        .loc 1 12 5 view .LVU14
        .cfi_endproc
.LFE13:
        .size   foo, .-foo
.Letext0:
...
Comment 5 Tom de Vries 2020-07-07 13:44:07 UTC
This seems to be var-track related.

Before var-track we have:
...
(debug_insn 23 41 24 5 (debug_marker) "test2.c":12:5 -1
     (nil))
(call_insn 24 23 25 5 (call (mem:QI (symbol_ref:DI ("abort") [flags 0x41]  <function_decl 0x7\
f376428b600 abort>) [0 __builtin_abort S1 A8])
        (const_int 0 [0])) "test2.c":12:5 795 {*call}
     (expr_list:REG_CALL_DECL (symbol_ref:DI ("abort") [flags 0x41]  <function_decl 0x7f37642\
8b600 abort>)
        (expr_list:REG_ARGS_SIZE (const_int 0 [0])
            (expr_list:REG_NORETURN (const_int 0 [0])
                (expr_list:REG_EH_REGION (const_int 0 [0])
                    (nil)))))
    (nil))
(barrier 25 24 39)
(note 39 25 0 NOTE_INSN_DELETED)
...
and after:
...
(call_insn:TI 24 41 80 5 (call (mem:QI (symbol_ref:DI ("abort") [flags 0x41]  <function_decl 0x7fc0f7701000 abort>) [0 __builtin_abort S1 A8])
        (const_int 0 [0])) "test2.c":12:5 666 {*call}
     (expr_list:REG_CALL_ARG_LOCATION (nil)
        (expr_list:REG_CALL_DECL (symbol_ref:DI ("abort") [flags 0x41]  <function_decl 0x7fc0f7701000 abort>)
            (expr_list:REG_ARGS_SIZE (const_int 0 [0])
                (expr_list:REG_NORETURN (const_int 0 [0])
                    (expr_list:REG_EH_REGION (const_int 0 [0])
                        (nil))))))
    (nil))
(note/c 80 24 79 (var_location a (entry_value:SI (reg:SI 5 di [ a ]))) NOTE_INSN_VAR_LOCATION)
(note/c 79 80 25 (var_location w (neg:SI (entry_value:SI (reg:SI 5 di [ a ])))) NOTE_INSN_VAR_LOCATION)
(barrier 25 79 39)
(note 39 25 0 NOTE_INSN_DELETED)
...
Comment 6 Tom de Vries 2020-07-07 14:03:52 UTC
A simple way of fixing this is:
...
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 899a5c0290d..4b143f6702b 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -6635,7 +6635,7 @@ add_with_sets (rtx_insn *insn, struct cselib_set *sets, int n_se
ts)
        std::swap (mos[n1], mos[n2]);
     }
 
-  if (CALL_P (insn))
+  if (CALL_P (insn) && ! find_reg_note (insn, REG_NORETURN, NULL))
     {
       micro_operation mo;
 
...

after which we have:
...
        .loc 1 12 5 view .LVU13
        call    abort
        .cfi_endproc
...
Comment 7 Tom de Vries 2020-07-07 14:13:41 UTC
A bit more subtle:
...
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 899a5c0290d..f94eb38f797 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -8880,6 +8880,10 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
 
   if (where != EMIT_NOTE_BEFORE_INSN)
     {
+      if (CALL_P (insn) && where == EMIT_NOTE_AFTER_CALL_INSN
+         && find_reg_note (insn, REG_NORETURN, NULL))
+       goto done;
+
       note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
       if (where == EMIT_NOTE_AFTER_CALL_INSN)
        NOTE_DURING_CALL_P (note) = true;
@@ -8901,6 +8905,7 @@ emit_note_insn_var_location (variable **varp, emit_note_data *data)
     }
   NOTE_VAR_LOCATION (note) = note_vl;
 
+ done:
   set_dv_changed (var->dv, false);
   gcc_assert (var->in_changed_variables);
   var->in_changed_variables = false;
...
which gets us:
...
        .loc 1 12 5 view .LVU13
        call    abort
.LVL5:
        .cfi_endproc
...