Bug 29517 - DWARF subprograms output by gas-2.39 have a 'void' return type
Summary: DWARF subprograms output by gas-2.39 have a 'void' return type
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: 2.39
: P2 normal
Target Milestone: ---
Assignee: Nick Clifton
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-08-24 00:22 UTC by Kevin Buettner
Modified: 2023-10-16 14:32 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
Proposed Patch (1.93 KB, patch)
2022-08-24 12:51 UTC, Nick Clifton
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Kevin Buettner 2022-08-24 00:22:02 UTC
We (myself and Frank Eigler) think we have found a problem with this
commit:

commit 591cc9fbbfd6d51131c0f1d4a92e7893edcc7a28
Author: Jan Beulich <jbeulich@suse.com>
Date:   Thu Apr 7 08:18:00 2022 +0200

    gas/Dwarf: record functions
    
    To help tools like addr2line looking up function names, in particular
    when dealing with e.g. PE/COFF binaries (linked from ELF objects), where
    there's no ELF symbol table to fall back to, emit minimalistic
    information for functions marked as such and having their size
    specified.
    ...

The GDB community recently encountered a regression when running the GDB testsuite on recent Fedora rawhide (rolling) releases which use binutils-2.39.  The log file shows this failure:

print /d (int) munmap (4198400, 4096)
Invalid cast.
(gdb) FAIL: gdb.base/break-main-file-remove-fail.exp: cmdline: get integer valueof "(int) munmap (4198400, 4096)"

Running GDB by hand with the testcase binary, I see:

(gdb) ptype munmap
type = void (void)

This explains the reason for the failure: GDB doesn't let us cast a void to an int.

Looking at the output (which ends up in the file "syms") produced by doing "maint print symbols syms" in GDB, I see:

Symtab for file ../sysdeps/unix/syscall-template.S at 0x1149b90
Compilation directory is /usr/src/debug/glibc-2.36.9000-2.fc38.x86_64/misc
Read from object file /lib64/ld-linux-x86-64.so.2 (0xfefbc0)
Language: asm
...
Blockvector:
...
block #000, object at 0x16fd620, 1 syms/buckets in 0x7ffff7feb960..0x7ffff7feb984
...
   void munmap(void); block object 0x16fd3a0, 0x7ffff7feb960..0x7ffff7feb984 section .text

This tells us the name of the object file from where GDB obtained the symbols / debug info as well as reaffirming the fact that GDB thinks that the return type of munmap is 'void'.  (According to its man page, the correct type of munmap should be int munmap(void *addr, size_t length).)

Now, looking at "readelf -w /lib64/ld-linux-x86-64.so.2", we can find the CU and DIE for munmap:

  Compilation Unit @ offset 0x350ac:
   Length:        0x61 (32-bit)
   Version:       5
   Unit Type:     DW_UT_compile (1)
   Abbrev Offset: 0xa21f
   Pointer Size:  8
 <0><350b8>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <350b9>   DW_AT_stmt_list   : 0x1f3fa
    <350bd>   DW_AT_low_pc      : 0x21960
    <350c5>   DW_AT_high_pc     : 36
    <350c6>   DW_AT_name        : (indirect string, offset: 0x186a): ../sysdeps/unix/syscall-template.S
    <350ca>   DW_AT_comp_dir    : (indirect string, offset: 0x26a9): /usr/src/debug/glibc-2.36.9000-2.fc38.x86_64/misc
    <350ce>   DW_AT_producer    : (indirect string, offset: 0x9f1): GNU AS 2.39
    <350d2>   DW_AT_language    : 32769	(MIPS assembler)
...
 <1><350f2>: Abbrev Number: 2 (DW_TAG_subprogram)
    <350f3>   DW_AT_name        : (indirect string, offset: 0x6703): munmap
    <350f7>   DW_AT_external    : 0
    <350f8>   DW_AT_low_pc      : 0x21960
    <35100>   DW_AT_high_pc     : 36

Note that there's no DW_AT_type attribute (which would specify the return type) for the munmap subprogram. As I understand it, this causes the return type to be void.  In section 3.3.2 of the DWARF 5 doc, it says "Debugging information entries for C void functions should not have an attribute for the return type."

However, a potential fix is suggested by section 5.2: "An unspecified (implicit, unknown, ambiguous or nonexistent) type is represented by a debugging information entry with the tag DW_TAG_unspecified_type."

Earlier Fedora releases including Fedora 35, 36, and 37 do not have a munmap subprogram in ld-linux-x86-64.so.2.  For these releases, "ptype munmap" from within GDB shows "type = <unknown return type> ()".  GDB can cast the unknown return type to an int which avoids the "invalid cast" error that we are currently seeing on rawhide.

This problem can be reproduced in a suitable environment by building upstream gdb and then, from within the 'gdb' directory, doing:

make check TESTS=gdb.base/break-main-file-remove-fail.exp

On rawhide, I see the following failures:

FAIL: gdb.base/break-main-file-remove-fail.exp: cmdline: get integer valueof "(int) munmap (4198400, 4096)"
FAIL: gdb.base/break-main-file-remove-fail.exp: file: get integer valueof "(int) munmap (4198400, 4096)"

If you wish to run GDB by hand using the test case for this test, do:

./gdb -q testsuite/outputs/gdb.base/break-main-file-remove-fail/break-main-file-remove-fail 

Then...

(gdb) b start
Breakpoint 1 at 0x40113a: file /ironwood1/sourceware-git/rawhide-master/bld/../../worktree-master/gdb/testsuite/gdb.base/break-main-file-remove-fail.c, line 26.
(gdb) run
Starting program: /mesquite2/sourceware-git/rawhide-master/bld/gdb/testsuite/outputs/gdb.base/break-main-file-remove-fail/break-main-file-remove-fail 

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.fedoraproject.org/>
Enable debuginfod for this session? (y or [n]) n
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, start ()
    at /ironwood1/sourceware-git/rawhide-master/bld/../../worktree-master/gdb/testsuite/gdb.base/break-main-file-remove-fail.c:26
26	}
(gdb) ptype munmap
type = void (void)

Regarding debuginfod, I see the same result whether it's enabled or not, but not enabling it makes it clear that the problematic debug info isn't coming from anything downloaded by debuginfod.
Comment 1 Jan Beulich 2022-08-24 07:02:05 UTC
(In reply to Kevin Buettner from comment #0)
> Note that there's no DW_AT_type attribute (which would specify the return
> type) for the munmap subprogram. As I understand it, this causes the return
> type to be void.  In section 3.3.2 of the DWARF 5 doc, it says "Debugging
> information entries for C void functions should not have an attribute for
> the return type."
> 
> However, a potential fix is suggested by section 5.2: "An unspecified
> (implicit, unknown, ambiguous or nonexistent) type is represented by a
> debugging information entry with the tag DW_TAG_unspecified_type."

Well, that's the route to take then for Dwarf3 and newer, I guess. I don't currently see what we could do about it for Dwarf2, though.
Comment 2 Nick Clifton 2022-08-24 12:51:13 UTC
Created attachment 14296 [details]
Proposed Patch

Hi Kevin, Hi Frank,

  Is this the sort of patch you had in mind ?

  I have not regression tested it yet, but I thought that it might be worth checking with you that this is what you were looking for.

Cheers
  Nick
Comment 3 Frank Ch. Eigler 2022-08-24 14:07:32 UTC
(lgtm on paper!)
Comment 4 Kevin Buettner 2022-08-24 15:35:29 UTC
(In reply to Nick Clifton from comment #2)

>   Is this the sort of patch you had in mind ?
> 
>   I have not regression tested it yet, but I thought that it might be worth
> checking with you that this is what you were looking for.

LGTM also.
Comment 5 Sourceware Commits 2022-08-25 10:49:12 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

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

commit 5578fbf672ee497ea19826edeb509f4cc3e825a8
Author: Nick Clifton <nickc@redhat.com>
Date:   Thu Aug 25 11:48:00 2022 +0100

    GAS: Add a return type tag to DWARF DIEs generated for function symbols.
    
            PR 29517
            * dwarf2dbg.c (GAS_ABBREV_COMP_UNIT): New defined constant.
            (GAS_ABBREV_SUBPROG): New defined constant.
            (GAS_ABBREV_NO_TYPE): New defined constant.
            (out_debug_abbrev): Use the new defined constants when emitting
            abbreviation numbers.  Generate an abbreviation for an unspecified
            type.
            (out_debug_info): Use the new defined constants when referring to
            abbreviations.  Generate a use of the no_type abbreviation.
            Reference the use when generating DIEs for functions.
            * testsuite/gas/elf/dwarf-3-func.d: Update to allow for newly
            extended output from the assembler.
            * testsuite/gas/elf/dwarf-5-func-global.d: Likewise.
            * testsuite/gas/elf/dwarf-5-func-local.d: Likewise.
            * testsuite/gas/elf/dwarf-5-func.d: Likewise.
Comment 6 Nick Clifton 2022-08-25 10:49:36 UTC
Right - I have applied the patch.
Comment 7 Sourceware Commits 2023-10-16 14:32:06 UTC
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

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

commit 1d45d90934b10862c00a22bcf4075815a785001b
Author: Tom de Vries <tdevries@suse.de>
Date:   Mon Oct 16 16:32:28 2023 +0200

    [gdb/symtab] Work around PR gas/29517
    
    When using glibc debuginfo generated with gas 2.39, we run into PR gas/29517:
    ...
    $ gdb -q -batch a.out -ex start -ex "p (char *)strstr (\"haha\", \"ah\")"
    Temporary breakpoint 1 at 0x40051b: file hello.c, line 6.
    
    Temporary breakpoint 1, main () at hello.c:6
    6         printf ("hello\n");
    Invalid cast.
    ...
    while without glibc debuginfo installed we get the expected result:
    ...
    $n = 0x7ffff7daa1b1 "aha"
    ...
    and likewise with glibc debuginfo generated with gas 2.40.
    
    The strstr ifunc resolves to __strstr_sse2_unaligned.  The problem is that gas
    generates dwarf that states that the return type is void:
    ...
    <1><3e1e58>: Abbrev Number: 2 (DW_TAG_subprogram)
        <3e1e59>   DW_AT_name        : __strstr_sse2_unaligned
        <3e1e5d>   DW_AT_external    : 1
        <3e1e5e>   DW_AT_low_pc      : 0xbbd2e
        <3e1e66>   DW_AT_high_pc     : 0xbc1c3
    ...
    while the return type should be a DW_TAG_unspecified_type, as is the case
    with gas 2.40.
    
    We can still use the workaround of casting to another function type for both
    __strstr_sse2_unaligned:
    ...
    (gdb) p ((char * (*) (const char *, const char *))__strstr_sse2_unaligned) \
      ("haha", "ah")
    $n = 0x7ffff7daa211 "aha"
    ...
    and strstr (which requires using *strstr to dereference the ifunc before we
    cast):
    ...
    gdb) p ((char * (*) (const char *, const char *))*strstr) ("haha", "ah")
    $n = 0x7ffff7daa251 "aha"
    ...
    but that's a bit cumbersome to use.
    
    Work around this in the dwarf reader, such that we have instead:
    ...
    (gdb) p (char *)strstr ("haha", "ah")
    $n = 0x7ffff7daa1b1 "aha"
    ...
    
    This also requires fixing producer_is_gcc to stop returning true for
    producer "GNU AS 2.39.0".
    
    Tested on x86_64-linux.
    
    Approved-By: Andrew Burgess <aburgess@redhat.com>
    
    PR symtab/30911
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30911