summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.python/py-type.exp
blob: 4990eeb7ddb4e7d8779902724a60282f50a419b8 (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
# 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"
}

# 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
  }
}


# 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
  }
}