diff options
author | Keith Seitz <keiths@redhat.com> | 2017-12-07 15:01:30 -0800 |
---|---|---|
committer | Keith Seitz <keiths@redhat.com> | 2017-12-07 15:01:30 -0800 |
commit | 883fd55ab1049333364479a7f5b0c7e61a310bac (patch) | |
tree | 7e62acd5cb4951e9b8faf934771e6c7a65b169c7 /gdb/testsuite/gdb.cp | |
parent | ec72db3ef415ebdcedaf36a1d83bd6624ec063e0 (diff) |
Record nested types
GDB currently does not track types defined in classes. Consider:
class A
{
public:
class B
{
public:
class C { };
};
};
(gdb) ptype A
type = class A {
<no data fields>
}
This patch changes this behavior so that GDB records these nested types
and displays them to the user when he has set the (new) "print type"
option "nested-type-limit."
Example:
(gdb) set print type nested-type-limit 1
(gdb) ptype A
type = class A {
<no data fields>
class A::B {
<no data fields>
};
}
(gdb) set print type nested-type-limit 2
type = class A {
<no data fields>
class A::B {
<no data fields>
class A::B::C {
<no data fields>
};
};
}
By default, the code maintains the status quo, that is, it will not print
any nested type definitions at all.
Testing is carried out via cp_ptype_class which required quite a bit of
modification to permit recursive calling (for the nested types). This
was most easily facilitated by turning the ptype command output into a
queue. Upshot: the test suite now has stack and queue data structures that
may be used by test writers.
gdb/ChangeLog
* NEWS (New commands): Mention set/show print type nested-type-limit.
* c-typeprint.c (c_type_print_base): Print out nested types.
* dwarf2read.c (struct typedef_field_list): Rename to ...
(struct decl_field_list): ... this. Change all uses.
(struct field_info) <nested_types_list, nested_types_list_count>:
New fields.
(add_partial_symbol): Look for nested type definitions in C++, too.
(dwarf2_add_typedef): Rename to ...
(dwarf2_add_type_defn): ... this.
(type_can_define_types): New function.
Update assertion to use type_can_define_types.
Permit NULL for a field's name.
(process_structure_scope): Handle child DIEs of types that can
define types.
Copy the list of nested types into the type struct.
* gdbtypes.h (struct typedef_field): Rename to ...
(struct decl_field): ... this. Change all uses.
[is_protected, is_private]: New fields.
(struct cplus_struct_type) <nested_types, nested_types_count>: New
fields.
(TYPE_NESTED_TYPES_ARRAY, TYPE_NESTED_TYPES_FIELD)
(TYPE_NESTED_TYPES_FIELD_NAME, TYPE_NESTED_TYPES_FIELD_TYPE)
(TYPE_NESTED_TYPES_COUNT, TYPE_NESTED_TYPES_FIELD_PROTECTED)
(TYPE_NESTED_TYPES_FIELD_PRIVATE): New macros.
* typeprint.c (type_print_raw_options, default_ptype_flags): Add
default value for print_nested_type_limit.
(print_nested_type_limit): New static variable.
(set_print_type_nested_types, show_print_type_nested_types): New
functions.
(_initialize_typeprint): Register new commands for set/show
`print-nested-type-limit'.
* typeprint.h (struct type_print_options) [print_nested_type_limit]:
New field.
gdb/testsuite/ChangeLog
* gdb.cp/nested-types.cc: New file.
* gdb.cp/nested-types.exp: New file.
* lib/cp-support.exp: Load data-structures.exp library.
(debug_cp_test_ptype_class): New global.
(cp_ptype_class_verbose, next_line): New procedures.
(cp_test_ptype_class): Add and document new parameter `recursive_qid'.
Add and document new return value.
Switch the list of lines to a queue.
Add support for new `type' key for nested type definitions.
Add debugging/troubleshooting messages.
* lib/data-structures.exp: New file.
gdb/doc/ChangeLog
* gdb.texinfo (Symbols): Document "set print type nested-type-limit"
and "show print type nested-type-limit".
Diffstat (limited to 'gdb/testsuite/gdb.cp')
-rw-r--r-- | gdb/testsuite/gdb.cp/nested-types.cc | 628 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/nested-types.exp | 322 |
2 files changed, 950 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.cp/nested-types.cc b/gdb/testsuite/gdb.cp/nested-types.cc new file mode 100644 index 0000000000..43beb577d7 --- /dev/null +++ b/gdb/testsuite/gdb.cp/nested-types.cc @@ -0,0 +1,628 @@ +/* Code in this file is generated. -*- buffer-read-only: t -*- vi:set ro: + See the procedure `make_source' in nested-types.exp. */ + +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2017 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 <http://www.gnu.org/licenses/>. */ + +struct S10 { + enum E10 {A10, B10, C10}; + union U10 { + int a; + char c; + }; + + int i10; + E10 e10; + U10 u10; + + struct S11 { + enum E11 {A11, B11, C11}; + union U11 { + int a; + char c; + }; + + int i11; + E11 e11; + U11 u11; + + struct S12 { + enum E12 {A12, B12, C12}; + union U12 { + int a; + char c; + }; + + int i12; + E12 e12; + U12 u12; + + struct S13 { + enum E13 {A13, B13, C13}; + union U13 { + int a; + char c; + }; + + int i13; + E13 e13; + U13 u13; + + struct S14 { + enum E14 {A14, B14, C14}; + union U14 { + int a; + char c; + }; + + int i14; + E14 e14; + U14 u14; + + struct S15 { + enum E15 {A15, B15, C15}; + union U15 { + int a; + char c; + }; + + int i15; + E15 e15; + U15 u15; + + struct S16 { + enum E16 {A16, B16, C16}; + union U16 { + int a; + char c; + }; + + int i16; + E16 e16; + U16 u16; + + struct S17 { + enum E17 {A17, B17, C17}; + union U17 { + int a; + char c; + }; + + int i17; + E17 e17; + U17 u17; + + struct S18 { + enum E18 {A18, B18, C18}; + union U18 { + int a; + char c; + }; + + int i18; + E18 e18; + U18 u18; + + struct S19 { + enum E19 {A19, B19, C19}; + union U19 { + int a; + char c; + }; + + int i19; + E19 e19; + U19 u19; + + }; + }; + }; + }; + }; + }; + }; + }; + }; + struct S21 { + enum E21 {A21, B21, C21}; + union U21 { + int a; + char c; + }; + + int i21; + E21 e21; + U21 u21; + + struct S22 { + enum E22 {A22, B22, C22}; + union U22 { + int a; + char c; + }; + + int i22; + E22 e22; + U22 u22; + + struct S23 { + enum E23 {A23, B23, C23}; + union U23 { + int a; + char c; + }; + + int i23; + E23 e23; + U23 u23; + + struct S24 { + enum E24 {A24, B24, C24}; + union U24 { + int a; + char c; + }; + + int i24; + E24 e24; + U24 u24; + + struct S25 { + enum E25 {A25, B25, C25}; + union U25 { + int a; + char c; + }; + + int i25; + E25 e25; + U25 u25; + + struct S26 { + enum E26 {A26, B26, C26}; + union U26 { + int a; + char c; + }; + + int i26; + E26 e26; + U26 u26; + + struct S27 { + enum E27 {A27, B27, C27}; + union U27 { + int a; + char c; + }; + + int i27; + E27 e27; + U27 u27; + + struct S28 { + enum E28 {A28, B28, C28}; + union U28 { + int a; + char c; + }; + + int i28; + E28 e28; + U28 u28; + + struct S29 { + enum E29 {A29, B29, C29}; + union U29 { + int a; + char c; + }; + + int i29; + E29 e29; + U29 u29; + + }; + }; + }; + }; + }; + }; + }; + }; + }; + struct S31 { + enum E31 {A31, B31, C31}; + union U31 { + int a; + char c; + }; + + int i31; + E31 e31; + U31 u31; + + struct S32 { + enum E32 {A32, B32, C32}; + union U32 { + int a; + char c; + }; + + int i32; + E32 e32; + U32 u32; + + struct S33 { + enum E33 {A33, B33, C33}; + union U33 { + int a; + char c; + }; + + int i33; + E33 e33; + U33 u33; + + struct S34 { + enum E34 {A34, B34, C34}; + union U34 { + int a; + char c; + }; + + int i34; + E34 e34; + U34 u34; + + struct S35 { + enum E35 {A35, B35, C35}; + union U35 { + int a; + char c; + }; + + int i35; + E35 e35; + U35 u35; + + struct S36 { + enum E36 {A36, B36, C36}; + union U36 { + int a; + char c; + }; + + int i36; + E36 e36; + U36 u36; + + struct S37 { + enum E37 {A37, B37, C37}; + union U37 { + int a; + char c; + }; + + int i37; + E37 e37; + U37 u37; + + struct S38 { + enum E38 {A38, B38, C38}; + union U38 { + int a; + char c; + }; + + int i38; + E38 e38; + U38 u38; + + struct S39 { + enum E39 {A39, B39, C39}; + union U39 { + int a; + char c; + }; + + int i39; + E39 e39; + U39 u39; + + }; + }; + }; + }; + }; + }; + }; + }; + }; + struct S41 { + enum E41 {A41, B41, C41}; + union U41 { + int a; + char c; + }; + + int i41; + E41 e41; + U41 u41; + + struct S42 { + enum E42 {A42, B42, C42}; + union U42 { + int a; + char c; + }; + + int i42; + E42 e42; + U42 u42; + + struct S43 { + enum E43 {A43, B43, C43}; + union U43 { + int a; + char c; + }; + + int i43; + E43 e43; + U43 u43; + + struct S44 { + enum E44 {A44, B44, C44}; + union U44 { + int a; + char c; + }; + + int i44; + E44 e44; + U44 u44; + + struct S45 { + enum E45 {A45, B45, C45}; + union U45 { + int a; + char c; + }; + + int i45; + E45 e45; + U45 u45; + + struct S46 { + enum E46 {A46, B46, C46}; + union U46 { + int a; + char c; + }; + + int i46; + E46 e46; + U46 u46; + + struct S47 { + enum E47 {A47, B47, C47}; + union U47 { + int a; + char c; + }; + + int i47; + E47 e47; + U47 u47; + + struct S48 { + enum E48 {A48, B48, C48}; + union U48 { + int a; + char c; + }; + + int i48; + E48 e48; + U48 u48; + + struct S49 { + enum E49 {A49, B49, C49}; + union U49 { + int a; + char c; + }; + + int i49; + E49 e49; + U49 u49; + + }; + }; + }; + }; + }; + }; + }; + }; + }; + struct S51 { + enum E51 {A51, B51, C51}; + union U51 { + int a; + char c; + }; + + int i51; + E51 e51; + U51 u51; + + struct S52 { + enum E52 {A52, B52, C52}; + union U52 { + int a; + char c; + }; + + int i52; + E52 e52; + U52 u52; + + struct S53 { + enum E53 {A53, B53, C53}; + union U53 { + int a; + char c; + }; + + int i53; + E53 e53; + U53 u53; + + struct S54 { + enum E54 {A54, B54, C54}; + union U54 { + int a; + char c; + }; + + int i54; + E54 e54; + U54 u54; + + struct S55 { + enum E55 {A55, B55, C55}; + union U55 { + int a; + char c; + }; + + int i55; + E55 e55; + U55 u55; + + struct S56 { + enum E56 {A56, B56, C56}; + union U56 { + int a; + char c; + }; + + int i56; + E56 e56; + U56 u56; + + struct S57 { + enum E57 {A57, B57, C57}; + union U57 { + int a; + char c; + }; + + int i57; + E57 e57; + U57 u57; + + struct S58 { + enum E58 {A58, B58, C58}; + union U58 { + int a; + char c; + }; + + int i58; + E58 e58; + U58 u58; + + struct S59 { + enum E59 {A59, B59, C59}; + union U59 { + int a; + char c; + }; + + int i59; + E59 e59; + U59 u59; + + }; + }; + }; + }; + }; + }; + }; + }; + }; +}; + +int +main () +{ + S10 s10; + S10::S11 s11; + S10::S11::S12 s12; + S10::S11::S12::S13 s13; + S10::S11::S12::S13::S14 s14; + S10::S11::S12::S13::S14::S15 s15; + S10::S11::S12::S13::S14::S15::S16 s16; + S10::S11::S12::S13::S14::S15::S16::S17 s17; + S10::S11::S12::S13::S14::S15::S16::S17::S18 s18; + S10::S11::S12::S13::S14::S15::S16::S17::S18::S19 s19; + + S10::S21 s21; + S10::S21::S22 s22; + S10::S21::S22::S23 s23; + S10::S21::S22::S23::S24 s24; + S10::S21::S22::S23::S24::S25 s25; + S10::S21::S22::S23::S24::S25::S26 s26; + S10::S21::S22::S23::S24::S25::S26::S27 s27; + S10::S21::S22::S23::S24::S25::S26::S27::S28 s28; + S10::S21::S22::S23::S24::S25::S26::S27::S28::S29 s29; + + S10::S31 s31; + S10::S31::S32 s32; + S10::S31::S32::S33 s33; + S10::S31::S32::S33::S34 s34; + S10::S31::S32::S33::S34::S35 s35; + S10::S31::S32::S33::S34::S35::S36 s36; + S10::S31::S32::S33::S34::S35::S36::S37 s37; + S10::S31::S32::S33::S34::S35::S36::S37::S38 s38; + S10::S31::S32::S33::S34::S35::S36::S37::S38::S39 s39; + + S10::S41 s41; + S10::S41::S42 s42; + S10::S41::S42::S43 s43; + S10::S41::S42::S43::S44 s44; + S10::S41::S42::S43::S44::S45 s45; + S10::S41::S42::S43::S44::S45::S46 s46; + S10::S41::S42::S43::S44::S45::S46::S47 s47; + S10::S41::S42::S43::S44::S45::S46::S47::S48 s48; + S10::S41::S42::S43::S44::S45::S46::S47::S48::S49 s49; + + S10::S51 s51; + S10::S51::S52 s52; + S10::S51::S52::S53 s53; + S10::S51::S52::S53::S54 s54; + S10::S51::S52::S53::S54::S55 s55; + S10::S51::S52::S53::S54::S55::S56 s56; + S10::S51::S52::S53::S54::S55::S56::S57 s57; + S10::S51::S52::S53::S54::S55::S56::S57::S58 s58; + S10::S51::S52::S53::S54::S55::S56::S57::S58::S59 s59; + return 0; +} diff --git a/gdb/testsuite/gdb.cp/nested-types.exp b/gdb/testsuite/gdb.cp/nested-types.exp new file mode 100644 index 0000000000..46edc30d5a --- /dev/null +++ b/gdb/testsuite/gdb.cp/nested-types.exp @@ -0,0 +1,322 @@ +# Copyright 2017 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 <http://www.gnu.org/licenses/>. + +# Test nested class definitions with the type printer. +# +# This test works by constructing a tree to represent "struct S10" in +# the corresponding source file. It then walks the nodes of this tree +# to construct input suitable for passing to cp_test_ptype_class. + +if {[skip_cplus_tests]} { continue } + +load_lib "cp-support.exp" + +standard_testfile .cc + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ + {debug c++}]} { + return -1 +} + +# Build the node given by ID (a number representing the struct S[ID] in +# the source file). +# +# For each node, stored as ::nodes(ID,ARG), where ARG is +# +# fields - list of fields [no children] +# children - list of types [children] + +proc build_node {id} { + global nodes + + # For any node, FIELDS is always the types i(N), e(N), u(N) + # CHILDREN is a list of nodes called [E(N), U(N)] S(N+1) + # + # The root (10) also has S(N+11), S(N+21), S(N+31), S(N+41) + + set nodes($id,fields) [list "int i$id" "E$id e$id" "U$id u$id"] + set nodes($id,children) {} + if {$id == 10} { + set limit 5 + } else { + set limit 1 + } + for {set i 0} {$i < $limit} {incr i} { + set n [expr {1 + $id + $i * 10}] + + # We don't build nodes which are multiples of 10 + # (the source only uses that at the root struct). + # We also don't create nodes not in the source file + # (id >= 60). + if {[expr {$n % 10}] != 0 && $n < 60} { + lappend nodes($id,children) $n + } + } +} + +# A helper procedure to indent the log output by LVL. This is used for +# debugging the tree, if ever necessary. + +proc indent {lvl} { + for {set i 0} {$i < $lvl} {incr i} { + send_log " " + } +} + +# For the given CHILD name and PARENT_LIST, return the fully qualified +# name of the child type. + +proc qual_name {child parent_list} { + if {[string range $child 0 2] != "int" && [llength $parent_list]} { + return "[join $parent_list ::]::$child" + } else { + return "$child" + } +} + +# Output the test source to the log. + +proc make_source {} { + # Output the structure. + test_nested_limit 10 true + + # Output main(). + send_log "int\nmain \(\)\n\{\n" + set plist {} + for {set i 10} {$i < 60} {incr i} { + if {$i > 10 && [expr {$i % 10}] == 0} { + incr i + set plist {"S10"} + send_log "\n" + } + send_log " [qual_name S$i $plist] s$i;\n" + lappend plist "S$i" + } + + send_log " return 0;\n" + send_log "\}\n" +} + +# Output to the log and/or create the result list for the fields of node ID. + +proc make_fields {result_var id parent_list indent_lvl log} { + upvar $result_var result + global nodes + + foreach type $nodes($id,fields) { + set s "[qual_name $type $parent_list];" + if {$log} { + indent $indent_lvl + send_log "$s\n" + } + lappend result [list "field" "public" "$s"] + } +} + +# Output to the log and/or create the result list for the union type in +# node ID. + +proc make_union {result_var id parent_list indent_lvl log} { + upvar $result_var result + + set s "[qual_name U$id $parent_list]" + set a "int a;" + set c "char c;" + lappend result [list "type" "public" "union" $s [list $a $c]] + if {$log} { + indent $indent_lvl + send_log "union $s \{\n" + indent [expr {$indent_lvl + 1}] + send_log "$a\n" + indent [expr {$indent_lvl + 1}] + send_log "$c\n" + indent $indent_lvl + send_log "\};\n" + } +} + +# Output to the log and/or create the result list for the enum type in +# node ID. + +proc make_enum {result_var id parent_list indent_lvl log} { + upvar $result_var result + + set s "[qual_name E$id $parent_list]" + set a "[qual_name A$id $parent_list]" + set b "[qual_name B$id $parent_list]" + set c "[qual_name C$id $parent_list]" + lappend result [list "type" "public" "enum" $s [list $a $b $c]] + + if {$log} { + indent $indent_lvl + send_log "enum $s \{$a, $b, $c\};\n" + } +} + +# Output to the log and/or create the result list for the node given by ID. +# +# LIMIT describes the number of nested types to output (corresponding to +# the "set print type nested-type-limit" command). +# PARENT_LIST is the list of parent nodes already seen. +# INDENT_LVL is the indentation level (used when LOG is true). + +proc node_result {result_var id limit parent_list indent_lvl log} { + upvar $result_var result + + # Start a new type list. + set my_name "S$id" + set s "[qual_name $my_name $parent_list]" + set my_result [list "type" "public" "struct" $s] + + if {$log} { + indent $indent_lvl + send_log "struct $my_name \{\n" + } else { + # Add this node to the parent list so that its name appears in + # qualified names, but only if we are not logging. [See immediately + # below.] + lappend parent_list "$my_name" + } + + # `ptype' outputs fields before type definitions, but in order to + # output compile-ready code, these must be output in reverse. + + if {!$log} { + # Output field list to a local children list. + set children_list {} + make_fields children_list $id $parent_list \ + [expr {$indent_lvl + 1}] $log + + # Output type definitions to the local children list. + # The first number of ID gives us the depth of the node. + if {[string index $id 1] < $limit || $limit < 0} { + make_enum children_list $id $parent_list \ + [expr {$indent_lvl + 1}] $log + make_union children_list $id $parent_list \ + [expr {$indent_lvl + 1}] $log + } + } else { + # Output type definitions to the local children list. + # The first number of ID gives us the depth of the node. + if {[string index $id 1] < $limit || $limit < 0} { + make_enum children_list $id $parent_list \ + [expr {$indent_lvl + 1}] $log + make_union children_list $id $parent_list \ + [expr {$indent_lvl + 1}] $log + send_log "\n" + } + + # Output field list to a local children list. + set children_list {} + make_fields children_list $id $parent_list \ + [expr {$indent_lvl + 1}] $log + send_log "\n" + } + + # Output the children to the local children list. + global nodes + if {[info exists nodes($id,children)]} { + foreach c $nodes($id,children) { + if {[string index $c 1] <= $limit || $limit < 0} { + node_result children_list $c $limit $parent_list \ + [expr {$indent_lvl + 1}] $log + } + } + } + + # Add this node's children to its result and add its result to + # its parent's results. + lappend my_result $children_list + lappend result $my_result + + if {$log} { + indent $indent_lvl + send_log "\};\n" + } +} + +# Test nested type definitions. LIMIT specifies how many nested levels +# of definitions to test. If LOG is true, output the tree to the log in +# a human-readable format mimicing the source code. +# +# Only test when not logging. Generating source code usable by the +# test is not quite the same as how GDB outputs it. + +proc test_nested_limit {limit log} { + set result {} + + if {!$log} { + # Set the number of nested definitions to print. + gdb_test_no_output "set print type nested-type-limit $limit" + + # Check the output of "show type print nested-type-limit" + if {$limit < 0} { + set lstr "unlimited" + } else { + set lstr $limit + } + gdb_test "show print type nested-type-limit" \ + "Will print $lstr nested types defined in a class" \ + "show print type nested-type-limit ($limit)" + } else { + send_log "Tree to $limit levels:\n" + } + + # Generate the result list. + node_result result 10 $limit {} 0 $log + + if {!$log} { + # The only output we check for is the contents of the struct, + # ignoring the leading "type = struct S10 {" and trailing "}" of + # the outermost node. + set result [lindex $result 0] + lassign $result type access key name children + cp_test_ptype_class $name "ptype $name (limit = $limit)" $key \ + $name $children + } +} + +# Build a tree of nodes describing the structures in the source file. + +# An array holding all the nodes +array set nodes {} +build_node 10 +for {set i 1} {$i < 6} {incr i} { + for {set j 1} {$j < 10} {incr j} { + build_node $i$j + } +} + +# Check relevant commands. + +# By default, we do not print nested type definitions. +gdb_test "show print type nested-type-limit" \ + "Will not print nested types defined in a class" \ + "show default print type nested-type-limit" + +# -1 means we print all nested types +test_nested_limit -1 false + +# Test the output of "show print type nested-type-limit" and +# ptype on the test source. + +for {set i 1} {$i < 9} {incr i} { + test_nested_limit $i false +} + +# To output the test code to the log, uncomment the following line: +#make_source + +unset -nocomplain nodes result |