diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5c5699e757..c37e281740 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,10 @@ +2018-12-24 Andrew Burgess + + * c-exp.y (field_name): Allow DOUBLE_KEYWORD, INT_KEYWORD, LONG, + SHORT, SIGNED_KEYWORD, and UNSIGNED tokens to act as a field + names. + (typename_stoken): New function. + 2018-12-24 Andrew Burgess * c-exp.y (field_name): New %token, and new rule. diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 98a0df3e19..996152d21f 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -113,6 +113,7 @@ static int type_aggregate_p (struct type *); static int parse_number (struct parser_state *par_state, const char *, int, int, YYSTYPE *); static struct stoken operator_stoken (const char *); +static struct stoken typename_stoken (const char *); static void check_parameter_typelist (VEC (type_ptr) *); static void write_destructor_name (struct parser_state *par_state, struct stoken); @@ -1645,9 +1646,21 @@ oper: OPERATOR NEW } ; - +/* This rule exists in order to allow some tokens that would not normally + match the 'name' rule to appear as fields within a struct. The example + that initially motivated this was the RISC-V target which models the + floating point registers as a union with fields called 'float' and + 'double'. The 'float' string becomes a TYPENAME token and can appear + anywhere a 'name' can, however 'double' is its own token, + DOUBLE_KEYWORD, and doesn't match the 'name' rule.*/ field_name : name + | DOUBLE_KEYWORD { $$ = typename_stoken ("double"); } + | INT_KEYWORD { $$ = typename_stoken ("int"); } + | LONG { $$ = typename_stoken ("long"); } + | SHORT { $$ = typename_stoken ("short"); } + | SIGNED_KEYWORD { $$ = typename_stoken ("signed"); } + | UNSIGNED { $$ = typename_stoken ("unsigned"); } ; name : NAME { $$ = $1.stoken; } @@ -1720,6 +1733,16 @@ operator_stoken (const char *op) return st; }; +/* Returns a stoken of the type named TYPE. */ + +static struct stoken +typename_stoken (const char *type) +{ + struct stoken st = { type, 0 }; + st.length = strlen (type); + return st; +}; + /* Return true if the type is aggregate-like. */ static int diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index fda5318990..47572ba14a 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-12-24 Andrew Burgess + + * gdb.dwarf2/dw2-unusual-field-names.c: New file. + * gdb.dwarf2/dw2-unusual-field-names.exp: New file. + 2018-12-24 Philippe Waroquiers * gdb.ada/bp_fun_addr/a.adb (a): Rename to bp_fun_addr. diff --git a/gdb/testsuite/gdb.dwarf2/dw2-unusual-field-names.c b/gdb/testsuite/gdb.dwarf2/dw2-unusual-field-names.c new file mode 100644 index 0000000000..091e475fb3 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-unusual-field-names.c @@ -0,0 +1,32 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2018 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 . */ + +struct foo +{ + int field; +}; + +struct foo obj = { 0 }; + +struct foo *ptr = &obj; + +int +main (void) +{ + return obj.field; +} + diff --git a/gdb/testsuite/gdb.dwarf2/dw2-unusual-field-names.exp b/gdb/testsuite/gdb.dwarf2/dw2-unusual-field-names.exp new file mode 100644 index 0000000000..6443acee24 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-unusual-field-names.exp @@ -0,0 +1,132 @@ +# Copyright 2018 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 that GDB can support accesing fields of a structure if the +# fields have non-standard names. Specifically, if the names are +# reserved C type names like 'double', 'float', 'int', etc. +# +# We don't expect to that such structures should be seen in real C +# code, but in some cases GDB will generate artificial structures, and +# in some cases, these type names are the obvious choice for field +# names. +# +# One specific example is RISC-V, the 64-bit floating point registers +# are represented as a structure with the field names 'float' and +# 'double'. + +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 dw2-unusual-field-names.c dw2-unusual-field-names.S +set asm_file [standard_output_file $srcfile2] + +# We need to know the size of integer and address types in order to +# write some of the debugging info we'd like to generate. +# +# For that, we ask GDB by debugging our test program. Any program +# would do, but since we already have one specifically for this +# testcase, might as well use that. +if [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] { + return -1 +} +set int_size [get_sizeof "int" -1] + +# Rebuild the test binary with the single field within the structure +# renamed to FIELD_NAME, then test that we can access the field +# through '.' and through '->'. +proc run_test { field_name } { + global asm_file testfile srcfile subdir srcdir + global int_size + + Dwarf::assemble $asm_file { + global srcdir subdir srcfile + global field_name int_size + + cu {} { + DW_TAG_compile_unit { + {DW_AT_language @DW_LANG_C} + {DW_AT_name dw2-unusual-field-names.c} + {DW_AT_comp_dir /tmp} + } { + declare_labels itype ptype stype + + itype: DW_TAG_base_type { + {DW_AT_byte_size $int_size DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name int} + } + + stype: DW_TAG_structure_type { + {DW_AT_name "foo"} + {DW_AT_byte_size $int_size DW_FORM_sdata} + } { + member { + {name $field_name} + {type :$itype} + {data_member_location 0 data1} + } + } + + ptype: DW_TAG_pointer_type { + {DW_AT_type :$stype} + } + + DW_TAG_variable { + {DW_AT_name obj} + {DW_AT_type :$stype} + {DW_AT_location { + DW_OP_addr [gdb_target_symbol obj] + } SPECIAL_expr} + {external 1 flag} + } + + DW_TAG_variable { + {DW_AT_name ptr} + {DW_AT_type :$ptype} + {DW_AT_location { + DW_OP_addr [gdb_target_symbol ptr] + } SPECIAL_expr} + {external 1 flag} + } + } + } + } + + if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 + } + + if ![runto_main] { + return -1 + } + + gdb_test "p obj.$field_name" " = 0" \ + "access a field named '$field_name' directly" + + gdb_test "p ptr->$field_name" " = 0" \ + "access a field named '$field_name' through a pointer" + + gdb_exit +} + +foreach field_name { double float char byte long int short unsigned signed } { + run_test $field_name +}