summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.python/py-type.exp
blob: 5613bc024f6f6b8c45fd8312c4d6c9c4aeea54d2 (plain)
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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# Copyright (C) 2009-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 <http://www.gnu.org/licenses/>.

# This file is part of the GDB testsuite.  It tests the mechanism
# of exposing types to Python.

load_lib gdb-python.exp

standard_testfile

if [get_compiler_info c++] {
    return -1
}

# Build inferior to language specification.
proc build_inferior {exefile lang} {
  global srcdir subdir srcfile testfile hex

  if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${exefile}" executable "debug $lang"] != "" } {
      untested "failed to compile in $lang mode"
      return -1
  }

  return 0
}

# Restart GDB.
proc restart_gdb {exefile} { 
  global srcdir subdir srcfile testfile hex

  gdb_exit
  gdb_start
  gdb_reinitialize_dir $srcdir/$subdir
  gdb_load ${exefile}

  if ![runto_main ] then {
      perror "couldn't run to breakpoint"
      return
  }
}

# Set breakpoint and run to that breakpoint.
proc runto_bp {bp} {
  gdb_breakpoint [gdb_get_line_number $bp]
  gdb_continue_to_breakpoint $bp
}

proc test_fields {lang} {
  with_test_prefix "test_fields" {
    global gdb_prompt

    # .fields() of a typedef should still return the underlying field list
    gdb_test "python print (len(gdb.parse_and_eval('ts').type.fields()))" "2" \
        "$lang typedef field list"

    if {$lang == "c++"} {
      # Test usage with a class
      gdb_py_test_silent_cmd "print (c)" "print value (c)" 1
      gdb_py_test_silent_cmd "python c = gdb.history (0)" "get value (c) from history" 1
      gdb_py_test_silent_cmd "python fields = c.type.fields()" "get fields from c.type" 1
      gdb_test "python print (len(fields))" "2" "check number of fields (c)"
      gdb_test "python print (fields\[0\].name)" "c" "check class field c name"
      gdb_test "python print (fields\[1\].name)" "d" "check class field d name"

      gdb_test "python print (c.type == gdb.parse_and_eval('d').type)" "False"
      gdb_test "python print (c.type == gdb.parse_and_eval('d').type.fields()\[0\].type)" \
	  "True"

      # Test fields of a method (its parameters)
      gdb_test "python print (len (gdb.parse_and_eval ('C::a_method').type.fields ()))" "3"
      gdb_test "python print (gdb.parse_and_eval ('C::a_method').type.fields ()\[0\].type)" "C \\* const"
      gdb_test "python print (gdb.parse_and_eval ('C::a_method').type.fields ()\[1\].type)" "int"
      gdb_test "python print (gdb.parse_and_eval ('C::a_method').type.fields ()\[2\].type)" "char"
      gdb_test "python print (gdb.parse_and_eval ('c')\['a_method'\].type.fields ()\[0\].type)" "C \\* const"

      gdb_test "python print (len (gdb.parse_and_eval ('C::a_const_method').type.fields ()))" "3"
      gdb_test "python print (gdb.parse_and_eval ('C::a_const_method').type.fields ()\[0\].type)" "const C \\* const"
      gdb_test "python print (gdb.parse_and_eval ('C::a_const_method').type.fields ()\[1\].type)" "int"
      gdb_test "python print (gdb.parse_and_eval ('C::a_const_method').type.fields ()\[2\].type)" "char"
      gdb_test "python print (gdb.parse_and_eval ('c')\['a_const_method'\].type.fields ()\[0\].type)" "const C \\* const"

      gdb_test "python print (len (gdb.parse_and_eval ('C::a_static_method').type.fields ()))" "2"
      gdb_test "python print (gdb.parse_and_eval ('C::a_static_method').type.fields ()\[0\].type)" "int"
      gdb_test "python print (gdb.parse_and_eval ('C::a_static_method').type.fields ()\[1\].type)" "char"
      gdb_test "python print (gdb.parse_and_eval ('c')\['a_static_method'\].type.fields ()\[0\].type)" "int"
    }

    # Test normal fields usage in structs.
    gdb_py_test_silent_cmd "print (st)" "print value (st)" 1
    gdb_py_test_silent_cmd "python st = gdb.history (0)" "get value (st) from history" 1
    gdb_py_test_silent_cmd "python fields = st.type.fields()" "get fields from st.type" 1
    gdb_test "python print (st.type.objfile.filename == gdb.current_progspace ().filename)" "True" \
      "check type.objfile"
    gdb_test "python print (len(fields))" "2" "check number of fields (st)"
    gdb_test "python print (fields\[0\].name)" "a" "check structure field a name"
    gdb_test "python print (fields\[1\].name)" "b" "check structure field b name"

    # Test that unamed fields have 'None' for name.
    gdb_py_test_silent_cmd "python ss = gdb.parse_and_eval('ss')" "init ss" 1
    gdb_py_test_silent_cmd "python ss_fields = ss.type.fields()" \
      "get fields from ss.type" 1
    gdb_test "python print(len(ss_fields))" "2" "check length of ss_fields"
    gdb_test "python print(ss_fields\[0\].name is None)" "True" \
      "Check ss_fields\[0\].name"
    gdb_test "python print(ss_fields\[1\].name is None)" "True" \
      "Check ss_fields\[1\].name"
    # Regression test for
    # http://sourceware.org/bugzilla/show_bug.cgi?id=12070.
    gdb_test "python print ('type' in dir(fields\[0\]))" "True" \
      "Check that dir includes name"

    # Test Python mapping behavior of gdb.Type for structs/classes
    gdb_test "python print (len(st.type))" "2" "check number of fields (st.type)"
    gdb_test "python print (st.type\['a'\].name)" "a" "check fields lookup by name"
    gdb_test "python print (\[v.bitpos for v in st.type.itervalues()\])" {\[0L?, 32L?\]} "Check fields iteration over values"
    gdb_test "python print (\[(n, v.bitpos) for (n, v) in st.type.items()\])" {\[\('a', 0L?\), \('b', 32L?\)\]} "Check fields items list"
    gdb_test "python print ('a' in st.type)" "True" "check field name exists test"
    gdb_test "python print ('nosuch' in st.type)" "False" "check field name nonexists test"
    gdb_test "python print (not not st.type)" "True" "check conversion to bool"

    # Test rejection of mapping operations on scalar types
    gdb_test "python print (len (st.type\['a'\].type))" "TypeError: Type is not a structure, union, enum, or function type.*"
    gdb_test "python print (st.type\['a'\].type.has_key ('x'))" "TypeError: Type is not a structure, union, enum, or function type.*"
    gdb_test "python print (st.type\['a'\].type\['x'\])" "TypeError: Type is not a structure, union, enum, or function type.*"
    gdb_test "python print (st.type\['a'\].type.keys ())" "TypeError: Type is not a structure, union, enum, or function type.*"

    # Test conversion to bool on scalar types
    gdb_test "python print (not not st.type\['a'\].type)" "True"
  
    # Test regression PR python/10805
    gdb_py_test_silent_cmd "print (ar)" "print value (ar)" 1
    gdb_py_test_silent_cmd "python ar = gdb.history (0)" "get value (ar) from history" 1
    gdb_test "python fields = ar.type.fields()"
    gdb_test "python print (len(fields))" "1" "check the number of fields"
    gdb_test "python print (fields\[0\].type)" "<range type>" "check array field type"

    # Test gdb.Type.array.
    gdb_test "python print (ar\[0\].cast(ar\[0\].type.array(1)))" \
        ".1, 2." "cast to array with one argument"
    gdb_test "python print (ar\[0\].cast(ar\[0\].type.array(0, 1)))" \
        ".1, 2." "cast to array with two arguments"

    gdb_test "python print (ar\[0\].type == ar\[0\].type)" "True"

    # Test gdb.Type.vector.
    # Note: vectors cast differently than arrays.  Here ar[0] is replicated
    # for the size of the vector.
    gdb_py_test_silent_cmd "print (vec_data_1)" "print value (vec_data_1)" 1
    gdb_py_test_silent_cmd "python vec_data_1 = gdb.history (0)" "get value (vec_data_1) from history" 1

    gdb_py_test_silent_cmd "print (vec_data_2)" "print value (vec_data_2)" 1
    gdb_py_test_silent_cmd "python vec_data_2 = gdb.history (0)" "get value (vec_data_2) from history" 1

    gdb_py_test_silent_cmd "python vec1 = vec_data_1.cast(ar\[0\].type.vector(1))" "set vec1" 1
    gdb_test "python print (vec1)" ".1, 1." "cast to vector with one argument"
    gdb_py_test_silent_cmd "python vec2 = vec_data_1.cast(ar\[0\].type.vector(0, 1))" "set vec2" 1
    gdb_test "python print (vec2)" ".1, 1." "cast to vector with two arguments"
    gdb_test "python print (vec1 == vec2)" "True"
    gdb_py_test_silent_cmd "python vec3 = vec_data_2.cast(ar\[0\].type.vector(1))" "set vec3" 1
    gdb_test "python print (vec1 == vec3)" "False"

    # Test fields of a function (its parameters)
    gdb_test "python print (len (gdb.parse_and_eval ('a_function').type.fields ()))" "2"
    gdb_test "python print (gdb.parse_and_eval ('a_function').type.fields ()\[0\].type)" "int"
    gdb_test "python print (gdb.parse_and_eval ('a_function').type.fields ()\[1\].type)" "char"

    # Test calling `fields` on a non-aggregate type.
    gdb_test "python gdb.lookup_type('int').fields()" "TypeError: Type is not a structure, union, enum, or function type.*"
  }
}

proc test_enums {} {
  with_test_prefix "test_enum" {
    gdb_py_test_silent_cmd "print (e)" "print value (e)" 1
    gdb_py_test_silent_cmd "python (e) = gdb.history (0)" "get value (e) from history" 1
    gdb_py_test_silent_cmd "python fields = e.type.fields()" "extract type fields from e" 1
    gdb_test "python print (len(fields))" "3" "check the number of enum fields"
    gdb_test "python print (fields\[0\].name)" "v1" "check enum field\[0\] name"
    gdb_test "python print (fields\[1\].name)" "v2" "check enum field\[1\]name"

    # Ditto but by mapping operations
    gdb_test "python print (len(e.type))" "3" "check the number of type fields"
    gdb_test "python print (e.type\['v1'\].name)" "v1" "check enum field lookup by name (v1)"
    gdb_test "python print (e.type\['v3'\].name)" "v3" "check enum field lookup by name (v3)"
    gdb_test "python print (\[v.enumval for v in e.type.itervalues()\])" {\[0L?, 1L?, 2L?\]} "Check num fields iteration over values"
    gdb_test "python print (\[(n, v.enumval) for (n, v) in e.type.items()\])" {\[\('v1', 0L?\), \('v2', 1L?\), \('v3', 2L?\)\]} "Check enum fields items list"
  }
}

proc test_base_class {} {
  with_test_prefix "test_base_class" {
    gdb_py_test_silent_cmd "print (d)" "print value (d)" 1
    gdb_py_test_silent_cmd "python d = gdb.history (0)" "get value (d) from history" 1
    gdb_py_test_silent_cmd "python fields = d.type.fields()" "extract type fields from d" 1
    gdb_test "python print (len(fields))" "3" "check the number of fields"
    gdb_test "python print (fields\[0\].is_base_class)" "True" "check base class (fields\[0\])"
    gdb_test "python print (fields\[1\].is_base_class)" "False" "check base class (fields\[1\])"
  }
}

proc test_range {} {
  with_test_prefix "test_range" {
    with_test_prefix "on ranged value" {
      # Test a valid range request.
      gdb_py_test_silent_cmd "print (ar)" "print value (ar)" 1
      gdb_py_test_silent_cmd "python ar = gdb.history (0)" "get value (ar) from history" 1
      gdb_test "python print (len(ar.type.range()))" "2" "check correct tuple length"
      gdb_test "python print (ar.type.range()\[0\])" "0" "check range low bound"
      gdb_test "python print (ar.type.range()\[1\])" "1" "check range high bound"
    }

    with_test_prefix "on ranged type" {
      # Test a range request on a ranged type.
      gdb_py_test_silent_cmd "print (ar)" "print value (ar)" 1
      gdb_py_test_silent_cmd "python ar = gdb.history (0)" "get value (ar) from history" 1
      gdb_py_test_silent_cmd "python fields = ar.type.fields()" "get fields" 1
      gdb_test "python print (fields\[0\].type.range()\[0\])" "0" "check range low bound"
      gdb_test "python print (fields\[0\].type.range()\[1\])" "1" "check range high bound"
    }

    with_test_prefix "on unranged value" {
      # Test where a range does not exist.
      gdb_py_test_silent_cmd "print (st)" "print value (st)" 1
      gdb_py_test_silent_cmd "python st = gdb.history (0)" "get value (st) from history" 1
      gdb_test "python print (st.type.range())" "RuntimeError: This type does not have a range.*" "check range for non ranged type."
    }
  }
}

# Some tests of template arguments.
proc test_template {} {
    gdb_py_test_silent_cmd \
	"python ttype = gdb.parse_and_eval('temvar').type" \
	"get type of temvar" \
	1

    gdb_test "python print (ttype.template_argument(0))" "D"
    gdb_test "python print (isinstance(ttype.template_argument(0), gdb.Type))" \
	"True"

    # The next two tests require a GCC that emits DW_TAG_template_*.
    # GCC 4.4 does not emit it, 4.5 and 6 do emit it.
    set have_older_gcc 0
    if {[test_compiler_info {gcc-[0-3]-*}]
	|| [test_compiler_info {gcc-4-[0-4]-*}]} {
	set have_older_gcc 1
    }
    if $have_older_gcc { setup_xfail *-*-* }
    gdb_test "python print (ttype.template_argument(1))" "23"
    if $have_older_gcc { setup_xfail *-*-* }
    gdb_test "python print (isinstance(ttype.template_argument(1), gdb.Value))" \
	"True"

    if {[test_compiler_info {gcc-[0-3]-*}]
	|| [test_compiler_info {gcc-4-[0-5]-*}]} {
	setup_xfail "gcc/46955" *-*-*
    }
    gdb_test "python print (ttype.template_argument(2))" "&C::c"
}

# Check the is_signed property of some types.
proc test_is_signed {lang} {
    if {$lang == "c++"} {
	gdb_test "python print(gdb.parse_and_eval ('c').type.is_signed)"  \
	"ValueError: Type must be a scalar type.*"
	gdb_test "python print(gdb.parse_and_eval ('&c').type.is_signed == False)" "True"
    }

    gdb_test "python print(gdb.parse_and_eval('global_unsigned_char').type.is_signed == False)" "True"
    gdb_test "python print(gdb.parse_and_eval('global_char').type.is_signed)" "True|False"
    gdb_test "python print(gdb.parse_and_eval('global_signed_char').type.is_signed == True)" "True"

    gdb_test "python print(gdb.parse_and_eval ('ss.x').type.is_signed == True)" "True"
    gdb_test "python print(gdb.parse_and_eval ('ss').type.is_signed)" \
	"ValueError: Type must be a scalar type.*"
    gdb_test "python print(gdb.parse_and_eval ('uu').type.is_signed)"  \
	"ValueError: Type must be a scalar type.*"
    gdb_test "python print(gdb.parse_and_eval ('uu.i').type.is_signed == True)" "True"
    gdb_test "python print(gdb.parse_and_eval ('uu.f').type.is_signed == True)" "True"
    gdb_test "python print(gdb.parse_and_eval ('uu.a').type.is_signed)"  \
	"ValueError: Type must be a scalar type.*"

    gdb_test "python print(gdb.parse_and_eval ('&ss.x').type.is_signed == False)" "True"
    gdb_test "python print(gdb.parse_and_eval ('&uu').type.is_signed == False)" "True"
}

# Compare the types of different symbols from the inferior, we're
# checking that the types of different sybols of the same declared
# type, are equal (in Python).
proc test_type_equality {} {

    foreach_with_prefix type { char int } {
	gdb_test_no_output "python v1 = gdb.parse_and_eval('global_unsigned_${type}')"
	gdb_test_no_output "python v2 = gdb.parse_and_eval('global_${type}')"
	gdb_test_no_output "python v3 = gdb.parse_and_eval('global_signed_${type}')"

	gdb_test_no_output "python t1 = v1.type"
	gdb_test_no_output "python t2 = v2.type"
	gdb_test_no_output "python t3 = v3.type"

	if { $type == "char" } {
	    # In C/C++ there's an interesting property of 'char' based types;
	    # 'signed char', 'unsigned char', and 'char' are all distinct
	    # types.  Weird, right?  Here we check that this property is
	    # visible to Python code.
	    gdb_test "python print(t1 != t2)" "True"
	    gdb_test "python print(t1 != t3)" "True"
	    gdb_test "python print(t2 != t3)" "True"
	} else {
	    # For 'int' type, when neither signed or unsigned is given
	    # we expect the type to be signed by default.
	    gdb_test "python print(t1 != t2)" "True"
	    gdb_test "python print(t1 != t3)" "True"
	    gdb_test "python print(t2 == t3)" "True"
	}
    }
}

# Test the gdb.Type.is_scalar property.
proc test_is_scalar { lang } {
    if {$lang == "c++"} {
	gdb_test "python print(gdb.parse_and_eval ('c').type.is_scalar)" "False"
	gdb_test "python print(gdb.parse_and_eval ('&c').type.is_scalar)" "True"
    }

    foreach type { char int } {
	gdb_test "python print(gdb.parse_and_eval('global_unsigned_${type}').type.is_scalar)" "True"
	gdb_test "python print(gdb.parse_and_eval('global_${type}').type.is_scalar)" "True"
	gdb_test "python print(gdb.parse_and_eval('global_signed_${type}').type.is_scalar)" "True"
    }

    gdb_test "python print(gdb.parse_and_eval ('ss.x').type.is_scalar)" "True"
    gdb_test "python print(gdb.parse_and_eval ('ss').type.is_scalar)" "False"
    gdb_test "python print(gdb.parse_and_eval ('uu').type.is_scalar)" "False"

    gdb_test "python print(gdb.parse_and_eval ('uu.i').type.is_scalar)" "True"
    gdb_test "python print(gdb.parse_and_eval ('uu.f').type.is_scalar)" "True"
    gdb_test "python print(gdb.parse_and_eval ('uu.a').type.is_scalar)"  "False"
    gdb_test "python print(gdb.parse_and_eval ('&ss.x').type.is_scalar)" "True"
}

# Perform C Tests.
if { [build_inferior "${binfile}" "c"] == 0 } {
  restart_gdb "${binfile}"

  # Skip all tests if Python scripting is not enabled.
  if { [skip_python_tests] } { continue }

  gdb_test "python print (gdb.lookup_type ('char').objfile)" "None"

  gdb_test "python print(gdb.lookup_type('char').array(1, 0))" \
      "char \\\[0\\\]"

  gdb_test "python print(gdb.lookup_type('char').array(1, -1))" \
      "Array length must not be negative.*"

  gdb_test "python print(gdb.lookup_type('int').optimized_out())" \
      "<optimized out>"

  set sint [get_sizeof int 0]
  gdb_test "python print(gdb.parse_and_eval('aligncheck').type.alignof)" \
      $sint

  with_test_prefix "lang_c" {
      runto_bp "break to inspect struct and array."
      test_fields "c"
      test_enums
      test_is_scalar "c"
      test_is_signed "c"
      test_type_equality
  }
}

# Perform C++ Tests.
if { [build_inferior "${binfile}-cxx" "c++"] == 0 } {
  restart_gdb "${binfile}-cxx"
  with_test_prefix "lang_cpp" {
      runto_bp "break to inspect struct and array."
      test_fields "c++"
      test_base_class
      test_range
      test_template
      test_enums
      test_is_scalar "c++"
      test_is_signed "c++"
      test_type_equality
  }
}