# This testcase is part of GDB, the GNU debugger. # Copyright 2017-2019 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 . # This testcase exercises the "ptype /o" feature, which can be used to # print the offsets and sizes of each field of a struct/union/class. standard_testfile .cc # Test only works on LP64 targets. That's how we guarantee that the # expected holes will be present in the struct. if { ![is_lp64_target] } { untested "test work only on lp64 targets" return 0 } if { [prepare_for_testing "failed to prepare" $testfile $srcfile \ { debug c++ }] } { return -1 } # Test general offset printing, ctor/dtor printing, union, formatting. gdb_test "ptype /o struct abc" \ [multi_line \ {/\* offset | size \*/ type = struct abc \{} \ { public:} \ {/\* 8 | 8 \*/ void \*field1;} \ {/\* 16:31 | 4 \*/ unsigned int field2 : 1;} \ {/\* XXX 7-bit hole \*/} \ {/\* XXX 3-byte hole \*/} \ {/\* 20 | 4 \*/ int field3;} \ {/\* 24 | 1 \*/ signed char field4;} \ {/\* XXX 7-byte hole \*/} \ {/\* 32 | 8 \*/ uint64_t field5;} \ {/\* 40 | 8 \*/ union \{} \ {/\* 8 \*/ void \*field6;} \ {/\* 4 \*/ int field7;} \ {} \ { /\* total size \(bytes\): 8 \*/} \ { \} field8;} \ {/\* 48 | 4 \*/ my_int_type field9;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 56 \*/} \ { \}}] # Test "ptype /oTM". gdb_test "ptype /oTM struct abc" \ [multi_line \ {/\* offset | size \*/ type = struct abc \{} \ { public:} \ {/\* 8 | 8 \*/ void \*field1;} \ {/\* 16:31 | 4 \*/ unsigned int field2 : 1;} \ {/\* XXX 7-bit hole \*/} \ {/\* XXX 3-byte hole \*/} \ {/\* 20 | 4 \*/ int field3;} \ {/\* 24 | 1 \*/ signed char field4;} \ {/\* XXX 7-byte hole \*/} \ {/\* 32 | 8 \*/ uint64_t field5;} \ {/\* 40 | 8 \*/ union \{} \ {/\* 8 \*/ void \*field6;} \ {/\* 4 \*/ int field7;} \ {} \ { /\* total size \(bytes\): 8 \*/} \ { \} field8;} \ {/\* 48 | 4 \*/ my_int_type field9;} \ {} \ { abc\(void\);} \ { ~abc\(\);} \ {} \ { typedef int my_int_type;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 56 \*/} \ { \}}] # Test "ptype /TMo". This should be the same as "ptype /o". gdb_test "ptype /TMo struct abc" \ [multi_line \ {/\* offset | size \*/ type = struct abc \{} \ { public:} \ {/\* 8 | 8 \*/ void \*field1;} \ {/\* 16:31 | 4 \*/ unsigned int field2 : 1;} \ {/\* XXX 7-bit hole \*/} \ {/\* XXX 3-byte hole \*/} \ {/\* 20 | 4 \*/ int field3;} \ {/\* 24 | 1 \*/ signed char field4;} \ {/\* XXX 7-byte hole \*/} \ {/\* 32 | 8 \*/ uint64_t field5;} \ {/\* 40 | 8 \*/ union \{} \ {/\* 8 \*/ void \*field6;} \ {/\* 4 \*/ int field7;} \ {} \ { /\* total size \(bytes\): 8 \*/} \ { \} field8;} \ {/\* 48 | 4 \*/ my_int_type field9;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 56 \*/} \ { \}}] # Test nested structs. gdb_test "ptype /o struct pqr" \ [multi_line \ {/\* offset | size \*/ type = struct pqr \{} \ {/\* 0 | 4 \*/ int ff1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 8 | 40 \*/ struct xyz \{} \ {/\* 8 | 4 \*/ int f1;} \ {/\* 12 | 1 \*/ signed char f2;} \ {/\* XXX 3-byte hole \*/} \ {/\* 16 | 8 \*/ void \*f3;} \ {/\* 24 | 24 \*/ struct tuv \{} \ {/\* 24 | 4 \*/ int a1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 32 | 8 \*/ signed char \*a2;} \ {/\* 40 | 4 \*/ int a3;} \ {} \ { /\* total size \(bytes\): 24 \*/} \ { \} f4;} \ {} \ { /\* total size \(bytes\): 40 \*/} \ { \} ff2;} \ {/\* XXX 28-byte hole \*/} \ {/\* 72 | 1 \*/ signed char ff3;} \ {/\* XXX 7-byte padding \*/} \ {} \ { /\* total size \(bytes\): 56 \*/} \ { \}}] # Test that the offset is properly reset when we are printing a union # and go inside two inner structs. # This also tests a struct inside a struct inside a union. gdb_test "ptype /o union qwe" \ [multi_line \ {/\* offset | size \*/ type = union qwe \{} \ {/\* 24 \*/ struct tuv \{} \ {/\* 0 | 4 \*/ int a1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 8 | 8 \*/ signed char \*a2;} \ {/\* 16 | 4 \*/ int a3;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 24 \*/} \ { \} fff1;} \ {/\* 40 \*/ struct xyz \{} \ {/\* 0 | 4 \*/ int f1;} \ {/\* 4 | 1 \*/ signed char f2;} \ {/\* XXX 3-byte hole \*/} \ {/\* 8 | 8 \*/ void \*f3;} \ {/\* 16 | 24 \*/ struct tuv \{} \ {/\* 16 | 4 \*/ int a1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 24 | 8 \*/ signed char \*a2;} \ {/\* 32 | 4 \*/ int a3;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 24 \*/} \ { \} f4;} \ {} \ { /\* total size \(bytes\): 40 \*/} \ { \} fff2;} \ {} \ { /\* total size \(bytes\): 40 \*/} \ { \}}] # Test printing a struct that contains a union, and that also # contains a struct. gdb_test "ptype /o struct poi" \ [multi_line \ {/\* offset | size \*/ type = struct poi \{} \ {/\* 0 | 4 \*/ int f1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 8 | 40 \*/ union qwe \{} \ {/\* 24 \*/ struct tuv \{} \ {/\* 8 | 4 \*/ int a1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 16 | 8 \*/ signed char \*a2;} \ {/\* 24 | 4 \*/ int a3;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 24 \*/} \ { \} fff1;} \ {/\* 40 \*/ struct xyz \{} \ {/\* 8 | 4 \*/ int f1;} \ {/\* 12 | 1 \*/ signed char f2;} \ {/\* XXX 3-byte hole \*/} \ {/\* 16 | 8 \*/ void \*f3;} \ {/\* 24 | 24 \*/ struct tuv \{} \ {/\* 24 | 4 \*/ int a1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 32 | 8 \*/ signed char \*a2;} \ {/\* 40 | 4 \*/ int a3;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 24 \*/} \ { \} f4;} \ {/\* XXX 32-byte padding \*/} \ {} \ { /\* total size \(bytes\): 40 \*/} \ { \} fff2;} \ {} \ { /\* total size \(bytes\): 40 \*/} \ { \} f2;} \ {/\* 72 | 2 \*/ uint16_t f3;} \ {/\* XXX 6-byte hole \*/} \ {/\* 80 | 56 \*/ struct pqr \{} \ {/\* 80 | 4 \*/ int ff1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 88 | 40 \*/ struct xyz \{} \ {/\* 88 | 4 \*/ int f1;} \ {/\* 92 | 1 \*/ signed char f2;} \ {/\* XXX 3-byte hole \*/} \ {/\* 96 | 8 \*/ void \*f3;} \ {/\* 104 | 24 \*/ struct tuv \{} \ {/\* 104 | 4 \*/ int a1;} \ {/\* XXX 4-byte hole \*/} \ {/\* 112 | 8 \*/ signed char \*a2;} \ {/\* 120 | 4 \*/ int a3;} \ {/\* XXX 4-byte padding \*/} \ {} \ { /\* total size \(bytes\): 24 \*/} \ { \} f4;} \ {} \ { /\* total size \(bytes\): 40 \*/} \ { \} ff2;} \ {/\* 152 | 1 \*/ signed char ff3;} \ {/\* XXX 7-byte padding \*/} \ {} \ { /\* total size \(bytes\): 56 \*/} \ { \} f4;} \ {} \ { /\* total size \(bytes\): 112 \*/} \ { \}}] # Test printing a struct with several bitfields, laid out in various # ways. # # Because dealing with bitfields and offsets is difficult, it can be # tricky to confirm that the output of this command is accurate. A # nice way to do that is to use GDB's "x" command and print the actual # memory layout of the struct. In order to differentiate between # bitfields and non-bitfield variables, one can assign "-1" to every # bitfield in the struct. An example of the output of "x" using # "struct tyu" is: # # (gdb) x/24xb &e # 0x7fffffffd540: 0xff 0xff 0xff 0x1f 0x00 0x00 0x00 0x00 # 0x7fffffffd548: 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff # 0x7fffffffd550: 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 gdb_test "ptype /o struct tyu" \ [multi_line \ {/\* offset | size \*/ type = struct tyu \{} \ {/\* 0:31 | 4 \*/ int a1 : 1;} \ {/\* 0:28 | 4 \*/ int a2 : 3;} \ {/\* 0: 5 | 4 \*/ int a3 : 23;} \ {/\* 3: 3 | 1 \*/ signed char a4 : 2;} \ {/\* XXX 3-bit hole \*/} \ {/\* XXX 4-byte hole \*/} \ {/\* 8 | 8 \*/ int64_t a5;} \ {/\* 16:27 | 4 \*/ int a6 : 5;} \ {/\* 16:56 | 8 \*/ int64_t a7 : 3;} \ {/\* XXX 7-byte padding \*/} \ {} \ { /\* total size \(bytes\): 24 \*/} \ { \}}] gdb_test "ptype /o struct asd" \ [multi_line \ {/\* offset | size \*/ type = struct asd \{} \ {/\* 0 | 32 \*/ struct asd::jkl \{} \ {/\* 0 | 8 \*/ signed char \*f1;} \ {/\* 8 | 8 \*/ union \{} \ {/\* 8 \*/ void \*ff1;} \ {} \ { /\* total size \(bytes\): 8 \*/} \ { \} f2;} \ {/\* 16 | 8 \*/ union \{} \ {/\* 8 \*/ signed char \*ff2;} \ {} \ { /\* total size \(bytes\): 8 \*/} \ { \} f3;} \ {/\* 24:27 | 4 \*/ int f4 : 5;} \ {/\* 24:26 | 4 \*/ unsigned int f5 : 1;} \ {/\* XXX 2-bit hole \*/} \ {/\* XXX 1-byte hole \*/} \ {/\* 26 | 2 \*/ short f6;} \ {} \ { /\* total size \(bytes\): 32 \*/} \ { \} f7;} \ {/\* 32 | 8 \*/ unsigned long f8;} \ {/\* 40 | 8 \*/ signed char \*f9;} \ {/\* 48:28 | 4 \*/ int f10 : 4;} \ {/\* 48:27 | 4 \*/ unsigned int f11 : 1;} \ {/\* 48:26 | 4 \*/ unsigned int f12 : 1;} \ {/\* 48:25 | 4 \*/ unsigned int f13 : 1;} \ {/\* 48:24 | 4 \*/ unsigned int f14 : 1;} \ {/\* XXX 7-byte hole \*/} \ {/\* 56 | 8 \*/ void \*f15;} \ {/\* 64 | 8 \*/ void \*f16;} \ {} \ { /\* total size \(bytes\): 72 \*/} \ { \}}] # Test that we don't print any header when issuing a "ptype /o" on a # non-struct, non-union, non-class type. gdb_test "ptype /o int" "int" gdb_test "ptype /o uint8_t" "char" # Test that the "whatis" command doesn't print anything related to the # "offsets" feature, even when receiving the "/o" parameter. set test "whatis /o asd" gdb_test_multiple "$test" "$test" { -re "^$test\r\ntype = asd\r\n$gdb_prompt $" { pass $test } } # Test that printing a struct with a static member of itself doesn't # get us into an infinite loop. gdb_test "ptype/o static_member" \ [multi_line \ {/\* offset | size \*/ type = struct static_member \{} \ { static static_member Empty;} \ {\/* 0 | 4 \*/ int abc;} \ {} \ { /\* total size \(bytes\): 4 \*/} \ { \}}]