Bug 28149 - debug info with wrong file association
Summary: debug info with wrong file association
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: 2.38
Assignee: Alan Modra
URL:
Keywords:
Depends on: 26778
Blocks:
  Show dependency treegraph
 
Reported: 2021-07-28 14:56 UTC by Bernd Edlinger
Modified: 2021-09-20 02:55 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2021-07-29 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Bernd Edlinger 2021-07-28 14:56:23 UTC
This was reported as gcc bug
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101575
but can also be seen as a gas bug, which means, that the
test-case defs.adb/defs.ads from a gdb testcase
https://sourceware.org/git/?p=binutils-gdb.git;a=tree;f=gdb/testsuite/gdb.ada/formatted_ref
(when compiled with -gdwarf-4)
has some mixed entries in the line table,
that is the source file from the .file <n> directive,
but line numbers from the assembler file.
That is due to

gas/dwarf2dbg.c

  if (num_of_auto_assigned)
    {
      /* Clear slots auto-assigned before the first .file <NUMBER>
         directive was seen.  */
      if (files_in_use != (num_of_auto_assigned + 1))
        abort ();
      for (i = 1; i < files_in_use; i++)
        files[i].filename = NULL;
      files_in_use = 0;
      num_of_auto_assigned = 0;
    }

so the previous file(s) are replaced with new files,
but the previous line data remain, and reference an
unrelated new file from the .file directive.
Comment 1 Richard Biener 2021-07-29 07:22:23 UTC
Note it is also undesirable to reference the (possibly temporary) filename of the assembler file as a "fix", even though that would seem to be the fix if the compiler asked the assembler to produce line info.  It's the behavior you get
when assembling without any .file directive.
Comment 2 Alan Modra 2021-07-29 07:52:05 UTC
More generally, you can ask gas to assemble multiple .s files to produce a single object.  How are conflicting file numbers supposed to be handled then?
Comment 3 Bernd Edlinger 2021-07-30 11:08:36 UTC
another test case I just discovered:

$ cat test1.c
asm("nop");
int main () 
{
  return 0;
}

$ gcc -g test1.c
$ readelf --debug-dump=decodedline a.out 
Contents of the .debug_line section:

CU: ./test1.c:
File name                            Line number    Starting address    View    Stmt
test1.c                                        5            0x401106               x
test1.c                                        3            0x401107               x
test1.c                                        4            0x40110b               x
test1.c                                        5            0x401110               x
test1.c                                        -            0x401112


The first line 5 is the line number of the nop from the .s file.
Comment 4 Alan Modra 2021-09-17 02:03:57 UTC
I can reproduce the comment #3 behaviour only when using -Wa,-gdwarf or similar gas options when using gcc-10.  gcc-11 and gcc-12 pass -gdwarf-5 to gas.  That seems to be the source of these problems, which is that -gdwarf* passed to gas means not only to select the DWARF level but also have gas generate its own DWARF line info.

So why is gcc passing -gdwarf-5 to gas?  That seems quite silly!  Can't gas figure the dwarf level out itself?  Note that current gas decides on dwarf5 if seeing a .file or .loc specifying file 0.
Comment 5 Fangrui Song 2021-09-17 08:03:30 UTC
(In reply to Alan Modra from comment #4)
> I can reproduce the comment #3 behaviour only when using -Wa,-gdwarf or
> similar gas options when using gcc-10.  gcc-11 and gcc-12 pass -gdwarf-5 to
> gas.  That seems to be the source of these problems, which is that -gdwarf*
> passed to gas means not only to select the DWARF level but also have gas
> generate its own DWARF line info.
> 
> So why is gcc passing -gdwarf-5 to gas?  That seems quite silly!  Can't gas
> figure the dwarf level out itself?  Note that current gas decides on dwarf5
> if seeing a .file or .loc specifying file 0.

https://gcc.gnu.org/pipermail/gcc-patches/2020-September/553527.html had the discussion for the -gdwarf-5 behavior.

gas' detection of DWARF v5 .debug_line was added later: https://sourceware.org/pipermail/binutils/2021-January/115000.html

If DWARF v6 or a future version ever bumps the line table version again (after v2->v5), perhaps having a directive is fine. LLVM folks do not object to a directive (https://reviews.llvm.org/D94882). I agree that passing -gdwarf-* to gas is probably not very useful.
Comment 6 Bernd Edlinger 2021-09-17 08:45:02 UTC
Note: latest gcc master has meanwhile a work around for this:

The work around for this issue is to emit a dummy .file
directive before the first function is compiled, unless
another .file directive was already emitted previously.

https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=96c82a16b2076891a9974d0f0e96a0b85fbc2df4
Comment 7 Sourceware Commits 2021-09-17 22:58:37 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=51298b330327a568358da069d9808f51c6cb1672

commit 51298b330327a568358da069d9808f51c6cb1672
Author: Alan Modra <amodra@gmail.com>
Date:   Fri Sep 17 09:08:15 2021 +0930

    PR28149, debug info with wrong file association
    
    gcc-11 and gcc-12 pass -gdwarf-5 to gas, in order to prime gas for
    DWARF 5 level debug info.  Unfortunately it seems there are cases
    where the compiler does not emit a .file or .loc dwarf debug directive
    before any machine instructions.  (Note that the .file directive
    typically emitted as the first line of assembly output doesn't count as
    a dwarf debug directive.  The dwarf .file has a file number before the
    file name string.)
    
    This patch delays allocation of file numbers for gas generated line
    debug info until the end of assembly, thus avoiding any clashes with
    compiler generated file numbers.  Two fixes for test case source are
    necessary;  A .loc can't use a file number that hasn't already been
    specified with .file.
    
    A followup patch will remove all the gas generated line info on
    seeing a .file directive.
    
            PR 28149
            * dwarf2dbg.c (num_of_auto_assigned): Delete.
            (current): Update initialisation.
            (set_or_check_view): Replace all accesses to view with u.view.
            (dwarf2_consume_line_info): Likewise.
            (dwarf2_directive_loc): Likewise.  Assert that we aren't generating
            line info.
            (dwarf2_gen_line_info_1): Don't call set_or_check_view on
            gas generated line entries.
            (dwarf2_gen_line_info): Set and track filenames for gas generated
            line entries.  Simplify generation of labels.
            (get_directory_table_entry): Use filename_cmp when comparing dirs.
            (do_allocate_filenum): New function.
            (dwarf2_where): Set u.filename and filenum to -1 for gas generated
            line entries.
            (dwarf2_directive_filename): Remove num_of_auto_assigned handling.
            (process_entries): Update view field access.  Call
            do_allocate_filenum.
            * dwarf2dbg.h (struct dwarf2_line_info): Add filename field in
            union aliasing view.
            * testsuite/gas/i386/dwarf2-line-3.s: Add .file directive.
            * testsuite/gas/i386/dwarf2-line-4.s: Likewise.
            * testsuite/gas/i386/dwarf2-line-4.d: Update expected output.
            * testsuite/gas/i386/dwarf4-line-1.d: Likewise.
            * testsuite/gas/i386/dwarf5-line-1.d: Likewise.
            * testsuite/gas/i386/dwarf5-line-2.d: Likewise.
Comment 8 Sourceware Commits 2021-09-17 22:58:42 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ef9768e37e34bec50aa8cbb0ce25708b06f09255

commit ef9768e37e34bec50aa8cbb0ce25708b06f09255
Author: Alan Modra <amodra@gmail.com>
Date:   Fri Sep 17 09:21:21 2021 +0930

    PR28149 part 2, purge generated line info
    
    Mixing compiler generated line info with gas generated line info is
    generally just confusing.  Also .loc directives with non-zero view
    fields might reference a previous .loc.  It becomes a little more
    tricky to locate that previous .loc if there might be gas generated
    line info present too.  Mind you, we turn off gas generation of line
    info on seeing compiler generated line info, so any reference back
    won't hit gas generated line info.  At least, if the view info is
    sane.  Unfortunately, gas needs to handle mangled source.
    
            PR 28149
            * dwarf2dbg.c (purge_generated_debug): New function.
            (dwarf2_directive_filename): Call the above.
            (out_debug_line): Don't segfault after purging.
            * testsuite/gas/i386/dwarf2-line-4.d: Update expected output.
            * testsuite/gas/i386/dwarf4-line-1.d: Likewise.
            * testsuite/gas/i386/dwarf5-line-1.d: Likewise.
            * testsuite/gas/i386/dwarf5-line-2.d: Likewise.
Comment 9 Alan Modra 2021-09-17 23:42:40 UTC
Fixed in binutils and gcc.
Comment 10 Sourceware Commits 2021-09-20 02:55:58 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=5b4846283c3d49138a58a3bb4d61ed3e2dfffff4

commit 5b4846283c3d49138a58a3bb4d61ed3e2dfffff4
Author: Alan Modra <amodra@gmail.com>
Date:   Mon Sep 20 11:30:41 2021 +0930

    Re: PR28149, debug info with wrong file association
    
    Fixes segfaults when building aarch64-linux kernel, due to only doing
    part of the work necessary when allocating file numbers late.  I'd
    missed looping over subsegments, which resulted in some u.filename
    entries left around and later interpreted as u.view.
    
            PR 28149
            * dwarf2dbg.c (purge_generated_debug): Iterate over subsegs too.
            (dwarf2_finish): Call do_allocate_filenum for all subsegs too,
            in a separate loop before subsegs are chained.