diff --git a/gdb/dwarf2/cu.c b/gdb/dwarf2/cu.c index 019165f6e6c5..b1fd688188a7 100644 --- a/gdb/dwarf2/cu.c +++ b/gdb/dwarf2/cu.c @@ -32,6 +32,7 @@ dwarf2_cu::dwarf2_cu (dwarf2_per_cu_data *per_cu, checked_producer (false), producer_is_gxx_lt_4_6 (false), producer_is_gcc_lt_4_3 (false), + producer_is_gcc_11 (false), producer_is_icc (false), producer_is_icc_lt_14 (false), producer_is_codewarrior (false), diff --git a/gdb/dwarf2/cu.h b/gdb/dwarf2/cu.h index 078479a56988..bce0a3de63a4 100644 --- a/gdb/dwarf2/cu.h +++ b/gdb/dwarf2/cu.h @@ -253,6 +253,7 @@ struct dwarf2_cu bool checked_producer : 1; bool producer_is_gxx_lt_4_6 : 1; bool producer_is_gcc_lt_4_3 : 1; + bool producer_is_gcc_11 : 1; bool producer_is_icc : 1; bool producer_is_icc_lt_14 : 1; bool producer_is_codewarrior : 1; diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index f7cb95b40cba..1a749eac334f 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -14320,6 +14320,7 @@ check_producer (struct dwarf2_cu *cu) { cu->producer_is_gxx_lt_4_6 = major < 4 || (major == 4 && minor < 6); cu->producer_is_gcc_lt_4_3 = major < 4 || (major == 4 && minor < 3); + cu->producer_is_gcc_11 = major == 11; } else if (producer_is_icc (cu->producer, &major, &minor)) { @@ -14464,6 +14465,19 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu, if (attr->form_is_constant ()) { LONGEST offset = attr->constant_value (0); + + /* Work around this GCC 11 bug, where it would erroneously use -1 + data member locations, instead of 0: + + Negative DW_AT_data_member_location + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101378 + */ + if (offset == -1 && cu->producer_is_gcc_11) + { + complaint (_("DW_AT_data_member_location value of -1, assuming 0")); + offset = 0; + } + field->set_loc_bitpos (offset * bits_per_byte); } else if (attr->form_is_section_offset ()) diff --git a/gdb/testsuite/gdb.dwarf2/negative-data-member-location.c b/gdb/testsuite/gdb.dwarf2/negative-data-member-location.c new file mode 100644 index 000000000000..6d8e8df01e9d --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/negative-data-member-location.c @@ -0,0 +1,31 @@ +/* Copyright (C) 2021-2022 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +struct the_struct +{ + /* Define the field as an array of char instead of an int to support targets + that have sizeof(int) != 4. */ + char x[4]; +}; + +struct the_struct s = { { 0x11, 0x22, 0x22, 0x11 } }; + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/negative-data-member-location.exp b/gdb/testsuite/gdb.dwarf2/negative-data-member-location.exp new file mode 100644 index 000000000000..57030d77134b --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/negative-data-member-location.exp @@ -0,0 +1,77 @@ +# Copyright 2021-2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test our workaround for a GCC 11 bug, where it sometimes puts a -1 value for +# DW_AT_data_member_location: +# +# Negative DW_AT_data_member_location +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101378 + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if { ![dwarf2_support] } { + return 0 +} + +standard_testfile .c -dw.S + +set asm_file [standard_output_file ${srcfile2}] + +Dwarf::assemble ${asm_file} { + cu {} { + DW_TAG_compile_unit { + {DW_AT_language @DW_LANG_C99} + {DW_AT_producer "GNU C++17 11.1.0 -mtune=generic -march=x86-64 -g3 -O0"} + {name ${::srcfile}} + } { + declare_labels int_label struct_label + + int_label: DW_TAG_base_type { + {DW_AT_byte_size 4 DW_FORM_udata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name "int"} + } + + struct_label: DW_TAG_structure_type { + {DW_AT_name "the_struct"} + {DW_AT_byte_size 4 DW_FORM_udata} + } { + DW_TAG_member { + {DW_AT_name "field"} + {DW_AT_type :$int_label} + {DW_AT_data_member_location -1 DW_FORM_sdata} + } + } + + DW_TAG_variable { + {DW_AT_name "s"} + {DW_AT_type :$struct_label} + {DW_AT_location {DW_OP_addr [gdb_target_symbol "s"]} SPECIAL_expr} + } + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} [list $srcfile $asm_file] {nodebug}] } { + return +} + +if { ![runto_main] } { + return +} + +gdb_test "print /x s" " = {field = 0x11222211}" +gdb_test "print /x s.field" " = 0x11222211"