Bug 78100 - DWARF symbols for an array sometimes missing the array length
Summary: DWARF symbols for an array sometimes missing the array length
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 6.2.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-10-24 20:00 UTC by Dima Kogan
Modified: 2017-12-12 00:27 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 7.0
Last reconfirmed: 2016-10-25 00:00:00


Attachments
test case (116 bytes, text/x-csrc)
2016-10-24 20:01 UTC, Dima Kogan
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dima Kogan 2016-10-24 20:00:34 UTC
Hi.

I'm using gcc 6.2 from Debian on an amd64 machine:

    dima@fatty:/tmp$ gcc --version

    gcc (Debian 6.2.0-9) 6.2.0 20161019
    Copyright (C) 2016 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Let's say I have the attached tiny C program: tst.c. I build and run it:

    dima@fatty:/tmp$ gcc -g -o tst tst.c

    dima@fatty:/tmp$ ./tst
    12

This is correct output: s has 3 32-bit integers in it for a total of 12 bytes.
Let me load this program in gdb, and see what gdb thinks sizeof(s) is:

    dima@fatty:/tmp$ gdb tst

    ...
    Reading symbols from tst...done.
    (gdb) p sizeof(s)
    $1 = 0

This is wrong. As stated before, the correct answer is 12, not 0. The problem is
that the DWARF data generated by gcc is incorrect:

    dima@fatty:/tmp$ readelf -wi tst

    Contents of the .debug_info section:

    ...
     <1><62>: Abbrev Number: 4 (DW_TAG_base_type)
        <63>   DW_AT_byte_size   : 4
        <64>   DW_AT_encoding    : 5	(signed)
        <65>   DW_AT_name        : int

     <1><303>: Abbrev Number: 12 (DW_TAG_array_type)
        <304>   DW_AT_type        : <0x62>
        <308>   DW_AT_sibling     : <0x30e>
     <2><30c>: Abbrev Number: 17 (DW_TAG_subrange_type)
     <2><30d>: Abbrev Number: 0

     <1><30e>: Abbrev Number: 18 (DW_TAG_variable)
        <30f>   DW_AT_name        : s
        <311>   DW_AT_decl_file   : 1
        <312>   DW_AT_decl_line   : 3
        <313>   DW_AT_type        : <0x303>
        <317>   DW_AT_external    : 1
        <317>   DW_AT_declaration : 1

     <1><317>: Abbrev Number: 19 (DW_TAG_variable)
        <318>   DW_AT_specification: <0x30e>
        <31c>   DW_AT_decl_line   : 4
        <31d>   DW_AT_location    : 9 byte block: 3 10 10 20 0 0 0 0 0 	(DW_OP_addr: 201010)

Here the 'extern' declaration appears in DIE 0x30e with the type in DIE 0x303.
This type die is an array of an unknown number of elements, which isn't wrong.

The instantiation is in DIE 0x317. This isn't extern, so we actually have a
location for this object. But instead of declaring the full type, we simply
reference the already-seen DIE 0x30e; this DIE doesn't know how many elements we
have, so this information doesn't appear in the DWARF data at all. Thus gdb
doesn't know we have 3 integers.

Removing the 'extern' declaration makes it work. Clang works as well.

For completeness, the code that reads this DWARF lives in array_size() in
elfutils/libdw/dwarf_aggregate_size.c. Given a DW_TAG_subrange_type it expects
either an DW_AT_count attribute or a DW_AT_upper_bound attribute, neither of
which we have here.

Thanks
Comment 1 Dima Kogan 2016-10-24 20:01:04 UTC
Created attachment 39876 [details]
test case
Comment 2 Dima Kogan 2016-10-24 21:26:15 UTC
For easier reading, the test program looks like this:

     #include <stdio.h>

     extern int s[];
     int s[] = { 1,2,3 };

     int main(void)
     {
         printf("%zd\n", sizeof(s));
         return 0;
     }
Comment 3 Richard Biener 2016-10-25 07:45:41 UTC
Confirmed.