1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
|
# Copyright 2017-2023 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 "whatis"/"ptype" of different typedef types, and of expressions
# involving casts to/from different typedefs.
#
# Particularly, when "whatis" is given a type name directly, it should
# strip one (and only one) typedef level. Otherwise, it should not
# strip any typedef at all. GDB used to incorrectly strip typedefs of
# expressions involving casts to typedef types. E.g., (gdb) print
# (int_typedef)0" shall result in a value of type "int_typedef", not
# "int".
standard_testfile
# Prepare for testing in language LANG. Lang can be "c" or "c++".
proc prepare {lang} {
global srcfile testfile
if [target_info exists no_long_long] {
set options [list debug additional_flags=-DNO_LONG_LONG]
} else {
set options [list debug]
}
if {$lang == "c++"} {
lappend options c++
set out $testfile-cxx
} else {
set out $testfile-c
}
if { [prepare_for_testing "failed to prepare" \
${out} [list $srcfile] $options] } {
return 0
}
if {![runto_main]} {
return 0
}
return 1
}
# The following list is layed out as a table. It is composed by
# sub-lists (lines), with each line representing one whatis/ptype
# test. The sub-list (line) elements (columns) are (in order):
#
# EXP - The user expression passed to whatis/ptype.
#
# WHATIS - What "whatis" should print.
#
# If the EXP column is a type name, then this will be the same type,
# with one (and only one) typedef level removed. Otherwise, this is
# the type of the expression on the first column, with all typedefs
# preserved.
#
# PTYPE - What "ptype" should print.
#
# This is always the type of the input type/expression stripped from
# all typedefs.
#
# LANGUAGE - If the line is language-specific, which language.
#
# This can be "c" or "c++".
#
# Columns in the table represent:
# EXP # whatis # ptype # language
set table {
{"void_typedef" "void" "void"}
{"void_typedef2" "void_typedef" "void"}
{"int_typedef" "int" "int"}
{"int_typedef2" "int_typedef" "int"}
{"v_int_typedef" "int_typedef" "int"}
{"v_int_typedef2" "int_typedef2" "int"}
{"float_typedef" "float" "float"}
{"float_typedef2" "float_typedef" "float"}
{"v_float_typedef" "float_typedef" "float"}
{"v_float_typedef2" "float_typedef2" "float"}
{"double_typedef" "double" "double"}
{"double_typedef2" "double_typedef" "double"}
{"v_double_typedef" "double_typedef" "double"}
{"v_double_typedef2" "double_typedef2" "double"}
{"long_double_typedef" "long double" "long double"}
{"long_double_typedef2" "long_double_typedef" "long double"}
{"v_long_double_typedef" "long_double_typedef" "long double"}
{"v_long_double_typedef2" "long_double_typedef2" "long double"}
{"colors_typedef" "(enum )?colors" "enum colors( : unsigned int)? {red, green, blue}"}
{"colors_typedef2" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"}
{"v_colors_typedef" "colors_typedef" "enum colors( : unsigned int)? {red, green, blue}"}
{"v_colors_typedef2" "colors_typedef2" "enum colors( : unsigned int)? {red, green, blue}"}
{"func_ftype" "void \\(void\\)" "void \\(void\\)"}
{"func_ftype2" "func_ftype" "void \\(void\\)"}
{"func_ftype *" "func_ftype \\*" "void \\(\\*\\)\\(void\\)"}
{"func_ftype2 *" "func_ftype2 \\*" "void \\(\\*\\)\\(void\\)"}
{"v_func_ftype" "func_ftype \\*" "void \\(\\*\\)\\(void\\)"}
{"v_func_ftype2" "func_ftype2 \\*" "void \\(\\*\\)\\(void\\)"}
{"v_t_struct_typedef" "t_struct_typedef" "struct t_struct {.* member;.*}"}
{"v_t_struct_typedef2" "t_struct_typedef2" "struct t_struct {.* member;.*}"}
{"v_t_struct_union_wrapper_typedef" "t_struct_union_wrapper_typedef" "union t_struct_union_wrapper {.*base;.*}"}
{"v_t_struct_union_wrapper_typedef2" "t_struct_union_wrapper_typedef2" "union t_struct_union_wrapper {.*base;.*}"}
{"v_uchar_array_t_struct_typedef" "uchar_array_t_struct_typedef" "unsigned char \\[.*\\]"}
{"v_uchar_array_t_struct_typedef2" "uchar_array_t_struct_typedef2" "unsigned char \\[.*\\]"}
{"v_ns_Struct_typedef" "ns_Struct_typedef" "struct ns::Struct {.* method.*}" "c++"}
{"ns_method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns::method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns_method_ptr_typedef2"
"ns_method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns::method_ptr_typedef2"
"ns::method_ptr_typedef"
"void \\(ns::Struct::\\*\\)\\(ns::Struct \\* const\\)"
"c++"}
{"ns::Struct::method"
"void \\(ns::Struct \\* const\\)"
"void \\(ns::Struct \\* const\\)"
"c++"}
}
# The 4th column above is optional. If present, it indicates that the
# line should only be tested in the specified language. This is a
# helper function that checks whether LINE's language matches LANG.
proc line_lang_match {line lang} {
if {[llength $line] <= 3} {
return true
}
set line_lang [lindex $line 3]
if {$line_lang == "" || $lang == $line_lang} {
return true
}
return false
}
# Run tests in language LANG.
proc run_tests {lang} {
global table
global gdb_prompt
# Test passing all EXP in the list/table above to whatis/ptype,
# and check what comes out.
with_test_prefix "whatis/ptype" {
foreach line $table {
set type [lindex $line 0]
set whatis [lindex $line 1]
set ptype [lindex $line 2]
if {![line_lang_match $line $lang]} {
continue
}
# GCC doesn't record the target type of "typedef of
# typedef of void" types in the DWARF. See
# <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81267>.
# Handle that case manually in order to be able to xfail
# it.
if {$type == "void_typedef2"} {
set test "whatis $type"
gdb_test_multiple $test $test {
-re "type = void\r\n$gdb_prompt $" {
# gcc/81267.
setup_xfail "*-*-*"
fail "$test (void)"
}
-re "type = void_typedef\r\n$gdb_prompt $" {
pass $test
}
}
} else {
gdb_test "whatis $type" "type = $whatis"
}
gdb_test "ptype $type" "type = $ptype"
}
}
# If floats and pointers have the same size on this architecture,
# then casting from array/function to float works, because
# arrays/functions first decay to pointers, and then GDB's cast is
# more general than a C cast and accepts any two types of the same
# length.
set float_ptr_same_size \
[get_integer_valueof "sizeof (float) == sizeof (void *)" -1]
# Ditto double.
set double_ptr_same_size \
[get_integer_valueof "sizeof (double) == sizeof (void *)" -1]
# Ditto long double.
set long_double_ptr_same_size \
[get_integer_valueof "sizeof (long double) == sizeof (void *)" -1]
# Test converting/casting all variables in the first column of the
# table to all types (found in the first column of the table).
# The aggregates are all defined to be the same size so that
# casting actually works. (GDB's casting operator is more general
# than a C cast.)
#
# The main idea here is testing all the different paths in the
# value casting code in GDB (value_cast), making sure typedefs are
# preserved.
with_test_prefix "cast" {
foreach line1 $table {
set from [lindex $line1 0]
if {![line_lang_match $line1 $lang]} {
continue
}
foreach line2 $table {
set to [lindex $line2 0]
set whatis [lindex $line2 1]
set ptype [lindex $line2 2]
if {![line_lang_match $line2 $lang]} {
continue
}
# We try all combinations, even those that don't
# parse, or are invalid, to catch the case of a
# regression making them inadvertently valid. For
# example, these conversions are invalid:
#
# float <-> array [iff sizeof pointer != sizeof float]
# array -> function (not function pointer)
# array -> member_ptr
#
# while these are invalid syntax:
#
# (anything) type
# (var) anything
# (method) anything [not method pointer]
# (float) method
#
if {([string match "v_*" $to]
|| (![string match "v_*" $from] && ![string match "*method" $from])
|| [string match "*method" $to])} {
gdb_test "whatis ($to) $from" "syntax error.*" "whatis ($to) $from (syntax)"
gdb_test "ptype ($to) $from" "syntax error.*" "ptype ($to) $from (syntax)"
} elseif {([string match "*float*" $from] && [string match "*array*" $to])
|| (!$float_ptr_same_size
&& ([string match "float*" $to] && [string match "*array*" $from]
|| [string match "float*" $to] && [string match "*method" $from]))
|| (!$double_ptr_same_size
&& ([string match "double*" $to] && [string match "*array*" $from]
|| [string match "double*" $to] && [string match "*method" $from]))
|| (!$long_double_ptr_same_size
&& ([string match "long_double*" $to] && [string match "*array*" $from]
|| [string match "long_double*" $to] && [string match "*method" $from]))
|| ([string match "*ftype" $to] && [string match "*array*" $from])
|| ([string match "*ftype2" $to] && [string match "*array*" $from])
|| ([string match "*ftype" $to] && [string match "*method" $from])
|| ([string match "*ftype2" $to] && [string match "*method" $from])
|| ([string match "*method_ptr*" $to] && [string match "*method" $from])
|| ([string match "*method_ptr*" $to] && [string match "*array*" $from])} {
gdb_test "whatis ($to) $from" "Invalid cast." "whatis ($to) $from (invalid)"
gdb_test "ptype ($to) $from" "Invalid cast." "ptype ($to) $from (invalid)"
} else {
gdb_test "whatis ($to) $from" "type = [string_to_regexp $to]"
gdb_test "ptype ($to) $from" "type = $ptype"
}
}
}
}
}
foreach_with_prefix lang {"c" "c++"} {
if {[prepare $lang]} {
run_tests $lang
}
}
|