diff options
-rw-r--r-- | gdb/ChangeLog | 27 | ||||
-rw-r--r-- | gdb/NEWS | 12 | ||||
-rw-r--r-- | gdb/c-typeprint.c | 8 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 7 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 113 | ||||
-rw-r--r-- | gdb/rust-lang.c | 2 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 11 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/ptype-offsets.exp | 562 | ||||
-rw-r--r-- | gdb/testsuite/gdb.rust/simple.exp | 10 | ||||
-rw-r--r-- | gdb/testsuite/gdb.rust/union.exp | 10 | ||||
-rw-r--r-- | gdb/typeprint.c | 83 | ||||
-rw-r--r-- | gdb/typeprint.h | 9 |
12 files changed, 559 insertions, 295 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 3e60116..fef76a0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,32 @@ 2021-04-25 Lancelot Six <lsix@lancelotsix.com> + PR gdb/22640 + * typeprint.h (struct type_print_options): Add print_in_hex + flag. + (struct print_offset_data): Add print_in_hex flag, add a + constructor accepting a type_print_options* argument. + * typeprint.c (type_print_raw_options, default_ptype_flags): Set + default value for print_in_hex. + (print_offset_data::indentation): Allow more horizontal space. + (print_offset_data::print_offset_data): Add ctor. + (print_offset_data::maybe_print_hole, print_offset_data::update): + Handle the print_in_hex flag. + (whatis_exp): Handle 'x' and 'd' flags. + (print_offsets_and_sizes_in_hex): Declare. + (set_print_offsets_and_sizes_in_hex): Create. + (show_print_offsets_and_sizes_in_hex): Create. + (_initialize_typeprint): Update help message for the ptype + command, register the 'set print type hex' and 'show print type + hex' commands. + * c-typeprint.c (c_print_type, c_type_print_base_struct_union) + (c_type_print_base): Construct the print_offset_data + object using the type_print_optons parameter. + * rust-lang.c (rust_language::print_type): Construct the + print_offset_data object using the type_print_optons parameter. + * NEWS: Mention the new flags of the ptype command. + +2021-04-25 Lancelot Six <lsix@lancelotsix.com> + * typeprint.h (struct type_print_options): Move before print_offset_data. @@ -101,6 +101,11 @@ show startup-quietly initialization file (e.g. ~/.config/gdb/gdbearlyinit) in order to affect GDB. +set print type hex on|off +show print type hex + When 'on', the 'ptype' command uses hexadecimal notation to print sizes + and offsets of struct members. When 'off', decimal notation is used. + * Changed commands break [PROBE_MODIFIER] [LOCATION] [thread THREADNUM] @@ -145,6 +150,13 @@ maintenance info sections line flag. It is now possible to filter which sections are printed even when -all-objects is passed. +ptype[/FLAGS] TYPE | EXPRESSION + The 'ptype' command has two new flags. When '/x' is set, hexadecimal + notation is used when printing sizes and offsets of struct members. + When '/d' is set, decimal notation is used when printing sizes and + offsets of struct members. Default behavior is given by 'show print + type hex'. + * Removed targets and native configurations ARM Symbian arm*-*-symbianelf* diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index 72616a5..0502d31 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -171,7 +171,7 @@ c_print_type (struct type *type, int show, int level, const struct type_print_options *flags) { - struct print_offset_data podata; + struct print_offset_data podata (flags); c_print_type_1 (type, varstring, stream, show, level, current_language->la_language, flags, &podata); @@ -188,7 +188,7 @@ c_print_type (struct type *type, enum language language, const struct type_print_options *flags) { - struct print_offset_data podata; + struct print_offset_data podata (flags); c_print_type_1 (type, varstring, stream, show, level, language, flags, &podata); @@ -1148,7 +1148,7 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream, int len = type->num_fields (); vptr_fieldno = get_vptr_fieldno (type, &basetype); - struct print_offset_data local_podata; + struct print_offset_data local_podata (flags); for (int i = TYPE_N_BASECLASSES (type); i < len; i++) { @@ -1723,7 +1723,7 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show, int level, const struct type_print_options *flags) { - struct print_offset_data podata; + struct print_offset_data podata (flags); c_type_print_base_1 (type, stream, show, level, current_language->la_language, flags, &podata); diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 08e3182..c22d4a6 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2021-04-25 Lancelot Six <lsix@lancelotsix.com> + + PR gdb/22640 + * gdb.texinfo (Symbols): Describe the 'x' and 'd' flags of the + ptype command, describe 'set print type hex' and 'show print + type hex' commands. Update 'ptype/o' examples. + 2021-04-21 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> * gdb.texinfo (GDB/MI Breakpoint Information): Update the diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index fd04aee..a068de6 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18885,6 +18885,21 @@ types. This command shows the current setting of typedef display when printing classes. +@kindex set print type hex +@item set print type hex +@itemx set print type hex on +@itemx set print type hex off + +When @value{GDBN} prints sizes and offsets of struct members, it can use +either the decimal or hexadecimal notation. You can select one or the +other either by passing the appropriate flag to @code{ptype}, or by using +the @command{set print type hex} command. + +@kindex show print type hex +@item show print type hex +This command shows whether the sizes and offsets of struct members are +printed in decimal or hexadecimal notation. + @kindex info address @cindex address of a symbol @item info address @var{symbol} @@ -18997,6 +19012,14 @@ exists in case you change the default with @command{set print type typedefs}. Print the offsets and sizes of fields in a struct, similar to what the @command{pahole} tool does. This option implies the @code{/tm} flags. +@item x +Use hexadecimal notation when printing offsets and sizes of fields in a +struct. + +@item d +Use decimal notation when printing offsets and sizes of fields in a +struct. + For example, given the following declarations: @smallexample @@ -19037,14 +19060,14 @@ Issuing a @kbd{ptype /o struct tuv} command would print: @smallexample (@value{GDBP}) ptype /o struct tuv -/* offset | size */ type = struct tuv @{ -/* 0 | 4 */ int a1; -/* XXX 4-byte hole */ -/* 8 | 8 */ char *a2; -/* 16 | 4 */ int a3; +/* offset | size */ type = struct tuv @{ +/* 0 | 4 */ int a1; +/* XXX 4-byte hole */ +/* 8 | 8 */ char *a2; +/* 16 | 4 */ int a3; - /* total size (bytes): 24 */ - @} + /* total size (bytes): 24 */ + @} @end smallexample Notice the format of the first column of comments. There, you can @@ -19059,34 +19082,34 @@ It is also possible to print offsets inside an union: @smallexample (@value{GDBP}) ptype /o union qwe -/* offset | size */ type = union qwe @{ -/* 24 */ struct tuv @{ -/* 0 | 4 */ int a1; -/* XXX 4-byte hole */ -/* 8 | 8 */ char *a2; -/* 16 | 4 */ int a3; - - /* total size (bytes): 24 */ - @} fff1; -/* 40 */ struct xyz @{ -/* 0 | 4 */ int f1; -/* 4 | 1 */ char f2; -/* XXX 3-byte hole */ -/* 8 | 8 */ void *f3; -/* 16 | 24 */ struct tuv @{ -/* 16 | 4 */ int a1; -/* XXX 4-byte hole */ -/* 24 | 8 */ char *a2; -/* 32 | 4 */ int a3; +/* offset | size */ type = union qwe @{ +/* 24 */ struct tuv @{ +/* 0 | 4 */ int a1; +/* XXX 4-byte hole */ +/* 8 | 8 */ char *a2; +/* 16 | 4 */ int a3; /* total size (bytes): 24 */ - @} f4; + @} fff1; +/* 40 */ struct xyz @{ +/* 0 | 4 */ int f1; +/* 4 | 1 */ char f2; +/* XXX 3-byte hole */ +/* 8 | 8 */ void *f3; +/* 16 | 24 */ struct tuv @{ +/* 16 | 4 */ int a1; +/* XXX 4-byte hole */ +/* 24 | 8 */ char *a2; +/* 32 | 4 */ int a3; + + /* total size (bytes): 24 */ + @} f4; + + /* total size (bytes): 40 */ + @} fff2; /* total size (bytes): 40 */ - @} fff2; - - /* total size (bytes): 40 */ - @} + @} @end smallexample In this case, since @code{struct tuv} and @code{struct xyz} occupy the @@ -19099,20 +19122,20 @@ bitfields: @smallexample (@value{GDBP}) ptype /o struct tyu -/* 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: 0 | 4 */ int a6 : 5; -/* 16: 5 | 8 */ int64_t a7 : 3; -"/* XXX 7-byte padding */ - - /* total size (bytes): 24 */ - @} +/* 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: 0 | 4 */ int a6 : 5; +/* 16: 5 | 8 */ int64_t a7 : 3; +/* XXX 7-byte padding */ + + /* total size (bytes): 24 */ + @} @end smallexample Note how the offset information is now extended to also include the diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c index a57ee98..8c4d209 100644 --- a/gdb/rust-lang.c +++ b/gdb/rust-lang.c @@ -1574,7 +1574,7 @@ rust_language::print_type (struct type *type, const char *varstring, struct ui_file *stream, int show, int level, const struct type_print_options *flags) const { - print_offset_data podata; + print_offset_data podata (flags); rust_internal_print_type (type, varstring, stream, show, level, flags, false, &podata); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 73f95b9..8f41b3a 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2021-04-25 Lancelot Six <lsix@lancelotsix.com> + + PR gdb/22640 + * gdb.base/ptype-offsets.exp: Add tests to verify the behavior + of 'ptype/ox' and 'ptype/od'. Check that 'set print type hex' + changes the default behavior of 'ptype/o'. Update to take into + account new horizontal layout. + * gdb.rust/simple.exp: Update ptype test to check new horizontal + layout. + * gdb.rust/union.exp: Same. + 2021-04-23 Andrew Burgess <andrew.burgess@embecosm.com> * gdb.base/info_sources.exp: Add new tests. diff --git a/gdb/testsuite/gdb.base/ptype-offsets.exp b/gdb/testsuite/gdb.base/ptype-offsets.exp index 0a0bbc8..cc017ad 100644 --- a/gdb/testsuite/gdb.base/ptype-offsets.exp +++ b/gdb/testsuite/gdb.base/ptype-offsets.exp @@ -35,216 +35,271 @@ if { [prepare_for_testing "failed to prepare" $testfile $srcfile \ # Test general offset printing, ctor/dtor printing, union, formatting. gdb_test "ptype /o struct abc" \ [string_to_regexp [multi_line \ -"/* offset | size */ type = struct abc \{" \ -" public:" \ -"/* 8 | 8 */ void *field1;" \ -"/* 16: 0 | 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;" \ +"/* offset | size */ type = struct abc \{" \ +" public:" \ +"/* 8 | 8 */ void *field1;" \ +"/* 16: 0 | 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 | 2 */ my_int_type field9;" \ -"/* XXX 6-byte padding */" \ +" /* total size (bytes): 8 */" \ +" \} field8;" \ +"/* 48 | 2 */ my_int_type field9;" \ +"/* XXX 6-byte padding */" \ "" \ -" /* total size (bytes): 56 */" \ -" \}"]] +" /* total size (bytes): 56 */" \ +" \}"]] + +# test "ptype /ox" +gdb_test "ptype /ox struct abc" \ + [string_to_regexp [multi_line \ +"/* offset | size */ type = struct abc {" \ +" public:" \ +"/* 0x0008 | 0x0008 */ void *field1;" \ +"/* 0x0010: 0x0 | 0x0004 */ unsigned int field2 : 1;" \ +"/* XXX 7-bit hole */" \ +"/* XXX 3-byte hole */" \ +"/* 0x0014 | 0x0004 */ int field3;" \ +"/* 0x0018 | 0x0001 */ signed char field4;" \ +"/* XXX 7-byte hole */" \ +"/* 0x0020 | 0x0008 */ uint64_t field5;" \ +"/* 0x0028 | 0x0008 */ union \{" \ +"/* 0x0008 */ void *field6;" \ +"/* 0x0004 */ int field7;" \ +"" \ +" /* total size (bytes): 8 */" \ +" \} field8;" \ +"/* 0x0030 | 0x0002 */ my_int_type field9;" \ +"/* XXX 6-byte padding */" \ +"" \ +" /* total size (bytes): 56 */" \ +" \}"]] # Test "ptype /oTM". gdb_test "ptype /oTM struct abc" \ [string_to_regexp [multi_line \ -"/* offset | size */ type = struct abc \{" \ -" public:" \ -"/* 8 | 8 */ void *field1;" \ -"/* 16: 0 | 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;" \ +"/* offset | size */ type = struct abc \{" \ +" public:" \ +"/* 8 | 8 */ void *field1;" \ +"/* 16: 0 | 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 | 2 */ my_int_type field9;" \ +" /* total size (bytes): 8 */" \ +" \} field8;" \ +"/* 48 | 2 */ my_int_type field9;" \ "" \ -" abc(void);" \ -" ~abc();" \ +" abc(void);" \ +" ~abc();" \ "" \ -" typedef short my_int_type;" \ -"/* XXX 6-byte padding */" \ +" typedef short my_int_type;" \ +"/* XXX 6-byte padding */" \ "" \ -" /* total size (bytes): 56 */" \ -" \}"]] +" /* total size (bytes): 56 */" \ +" \}"]] # Test "ptype /TMo". This should be the same as "ptype /o". gdb_test "ptype /TMo struct abc" \ [string_to_regexp [multi_line \ -"/* offset | size */ type = struct abc \{" \ -" public:" \ -"/* 8 | 8 */ void *field1;" \ -"/* 16: 0 | 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;" \ +"/* offset | size */ type = struct abc \{" \ +" public:" \ +"/* 8 | 8 */ void *field1;" \ +"/* 16: 0 | 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 | 2 */ my_int_type field9;" \ -"/* XXX 6-byte padding */" \ +" /* total size (bytes): 8 */" \ +" \} field8;" \ +"/* 48 | 2 */ my_int_type field9;" \ +"/* XXX 6-byte padding */" \ "" \ -" /* total size (bytes): 56 */" \ -" \}"]] +" /* total size (bytes): 56 */" \ +" \}"]] # Test nested structs. gdb_test "ptype /o struct pqr" \ [string_to_regexp [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;" \ -"/* XXX 4-byte padding */" \ +"/* 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;" \ +"/* XXX 4-byte padding */" \ "" \ -" /* total size (bytes): 24 */" \ -" \} f4;" \ +" /* total size (bytes): 24 */" \ +" \} f4;" \ "" \ -" /* total size (bytes): 40 */" \ -" \} ff2;" \ -"/* 48 | 1 */ signed char ff3;" \ -"/* XXX 7-byte padding */" \ +" /* total size (bytes): 40 */" \ +" \} ff2;" \ +"/* 48 | 1 */ signed char ff3;" \ +"/* XXX 7-byte padding */" \ "" \ -" /* total size (bytes): 56 */" \ -" \}"]] +" /* 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" \ +# Test nested struct with /x +gdb_test "ptype /ox struct pqr" \ [string_to_regexp [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 */" \ +"/* offset | size */ type = struct pqr \{" \ +"/* 0x0000 | 0x0004 */ int ff1;" \ +"/* XXX 4-byte hole */" \ +"/* 0x0008 | 0x0028 */ struct xyz \{" \ +"/* 0x0008 | 0x0004 */ int f1;" \ +"/* 0x000c | 0x0001 */ signed char f2;" \ +"/* XXX 3-byte hole */" \ +"/* 0x0010 | 0x0008 */ void *f3;" \ +"/* 0x0018 | 0x0018 */ struct tuv \{" \ +"/* 0x0018 | 0x0004 */ int a1;" \ +"/* XXX 4-byte hole */" \ +"/* 0x0020 | 0x0008 */ signed char *a2;" \ +"/* 0x0028 | 0x0004 */ 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): 24 */" \ +" \} f4;" \ "" \ -" /* total size (bytes): 40 */" \ -" \} fff2;" \ +" /* total size (bytes): 40 */" \ +" \} ff2;" \ +"/* 0x0030 | 0x0001 */ signed char ff3;" \ +"/* XXX 7-byte padding */" \ "" \ -" /* total size (bytes): 40 */" \ -" \}"]] +" /* total size (bytes): 56 */" \ +" \}"]] -# Test printing a struct that contains a union, and that also -# contains a struct. -gdb_test "ptype /o struct poi" \ + +# 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" \ [string_to_regexp [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 */" \ +"/* 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 \{" \ -"/* 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 */" \ +"/* 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;" \ -"/* XXX 32-byte padding */" \ "" \ " /* total size (bytes): 40 */" \ -" \} f2;" \ -"/* 48 | 2 */ uint16_t f3;" \ -"/* XXX 6-byte hole */" \ -"/* 56 | 56 */ struct pqr \{" \ -"/* 56 | 4 */ int ff1;" \ -"/* XXX 4-byte hole */" \ -"/* 64 | 40 */ struct xyz \{" \ -"/* 64 | 4 */ int f1;" \ -"/* 68 | 1 */ signed char f2;" \ -"/* XXX 3-byte hole */" \ -"/* 72 | 8 */ void *f3;" \ -"/* 80 | 24 */ struct tuv \{" \ -"/* 80 | 4 */ int a1;" \ -"/* XXX 4-byte hole */" \ -"/* 88 | 8 */ signed char *a2;" \ -"/* 96 | 4 */ int a3;" \ -"/* XXX 4-byte padding */" \ +" \}"]] + +# Test printing a struct that contains a union, and that also +# contains a struct. +gdb_test "ptype /o struct poi" \ + [string_to_regexp [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 */" \ -" \} f4;" \ +" \} 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;" \ +"" \ +" /* total size (bytes): 40 */" \ +" \} fff2;" \ +"/* XXX 32-byte padding */" \ "" \ " /* total size (bytes): 40 */" \ -" \} ff2;" \ -"/* 104 | 1 */ signed char ff3;" \ -"/* XXX 7-byte padding */" \ +" \} f2;" \ +"/* 48 | 2 */ uint16_t f3;" \ +"/* XXX 6-byte hole */" \ +"/* 56 | 56 */ struct pqr \{" \ +"/* 56 | 4 */ int ff1;" \ +"/* XXX 4-byte hole */" \ +"/* 64 | 40 */ struct xyz \{" \ +"/* 64 | 4 */ int f1;" \ +"/* 68 | 1 */ signed char f2;" \ +"/* XXX 3-byte hole */" \ +"/* 72 | 8 */ void *f3;" \ +"/* 80 | 24 */ struct tuv \{" \ +"/* 80 | 4 */ int a1;" \ +"/* XXX 4-byte hole */" \ +"/* 88 | 8 */ signed char *a2;" \ +"/* 96 | 4 */ int a3;" \ +"/* XXX 4-byte padding */" \ "" \ -" /* total size (bytes): 56 */" \ -" \} f4;" \ +" /* total size (bytes): 24 */" \ +" \} f4;" \ +"" \ +" /* total size (bytes): 40 */" \ +" \} ff2;" \ +"/* 104 | 1 */ signed char ff3;" \ +"/* XXX 7-byte padding */" \ +"" \ +" /* total size (bytes): 56 */" \ +" \} f4;" \ "" \ -" /* total size (bytes): 112 */" \ -" \}"]] +" /* total size (bytes): 112 */" \ +" \}"]] # Test printing a struct with several bitfields, laid out in various # ways. @@ -263,58 +318,58 @@ gdb_test "ptype /o struct poi" \ # 0x7fffffffd550: 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 gdb_test "ptype /o struct tyu" \ [string_to_regexp [multi_line \ -"/* offset | size */ type = struct tyu \{" \ -"/* 0: 0 | 4 */ int a1 : 1;" \ -"/* 0: 1 | 4 */ int a2 : 3;" \ -"/* 0: 4 | 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: 0 | 4 */ int a6 : 5;" \ -"/* 16: 5 | 8 */ int64_t a7 : 3;" \ -"/* XXX 7-byte padding */" \ -"" \ -" /* total size (bytes): 24 */" \ -" \}"]] +"/* offset | size */ type = struct tyu \{" \ +"/* 0: 0 | 4 */ int a1 : 1;" \ +"/* 0: 1 | 4 */ int a2 : 3;" \ +"/* 0: 4 | 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: 0 | 4 */ int a6 : 5;" \ +"/* 16: 5 | 8 */ int64_t a7 : 3;" \ +"/* XXX 7-byte padding */" \ +"" \ +" /* total size (bytes): 24 */" \ +" \}"]] gdb_test "ptype /o struct asd" \ [string_to_regexp [multi_line \ -"/* offset | size */ type = struct asd \{" \ -"/* 0 | 32 */ struct asd::jkl \{" \ -"/* 0 | 8 */ signed char *f1;" \ -"/* 8 | 8 */ union \{" \ -"/* 8 */ void *ff1;" \ +"/* 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 */" \ +" \} f2;" \ +"/* 16 | 8 */ union \{" \ +"/* 8 */ signed char *ff2;" \ "" \ -" /* total size (bytes): 8 */" \ -" \} f3;" \ -"/* 24: 0 | 4 */ int f4 : 5;" \ -"/* 24: 5 | 4 */ unsigned int f5 : 1;" \ -"/* XXX 2-bit hole */" \ -"/* XXX 1-byte hole */" \ -"/* 26 | 2 */ short f6;" \ -"/* XXX 4-byte padding */" \ -"" \ -" /* total size (bytes): 32 */" \ -" \} f7;" \ -"/* 32 | 8 */ unsigned long f8;" \ -"/* 40 | 8 */ signed char *f9;" \ -"/* 48: 0 | 4 */ int f10 : 4;" \ -"/* 48: 4 | 4 */ unsigned int f11 : 1;" \ -"/* 48: 5 | 4 */ unsigned int f12 : 1;" \ -"/* 48: 6 | 4 */ unsigned int f13 : 1;" \ -"/* 48: 7 | 4 */ unsigned int f14 : 1;" \ -"/* XXX 7-byte hole */" \ -"/* 56 | 8 */ void *f15;" \ -"/* 64 | 8 */ void *f16;" \ -"" \ -" /* total size (bytes): 72 */" \ -" \}"]] +" /* total size (bytes): 8 */" \ +" \} f3;" \ +"/* 24: 0 | 4 */ int f4 : 5;" \ +"/* 24: 5 | 4 */ unsigned int f5 : 1;" \ +"/* XXX 2-bit hole */" \ +"/* XXX 1-byte hole */" \ +"/* 26 | 2 */ short f6;" \ +"/* XXX 4-byte padding */" \ +"" \ +" /* total size (bytes): 32 */" \ +" \} f7;" \ +"/* 32 | 8 */ unsigned long f8;" \ +"/* 40 | 8 */ signed char *f9;" \ +"/* 48: 0 | 4 */ int f10 : 4;" \ +"/* 48: 4 | 4 */ unsigned int f11 : 1;" \ +"/* 48: 5 | 4 */ unsigned int f12 : 1;" \ +"/* 48: 6 | 4 */ unsigned int f13 : 1;" \ +"/* 48: 7 | 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. @@ -334,24 +389,83 @@ gdb_test_multiple "$test" "$test" { # get us into an infinite loop. gdb_test "ptype/o static_member" \ [string_to_regexp [multi_line \ -"/* offset | size */ type = struct static_member \{" \ -" static static_member Empty;" \ -"/* 0 | 4 */ int abc;" \ +"/* offset | size */ type = struct static_member \{" \ +" static static_member Empty;" \ +"/* 0 | 4 */ int abc;" \ "" \ -" /* total size (bytes): 4 */" \ -" \}"]] +" /* total size (bytes): 4 */" \ +" \}"]] # Test that the "no data fields" text is indented properly. gdb_test "ptype/o empty_member" \ [string_to_regexp [multi_line \ -"/* offset | size */ type = struct empty_member \{" \ -"/* 0 | 1 */ struct {" \ -" <no data fields>" \ +"/* offset | size */ type = struct empty_member \{" \ +"/* 0 | 1 */ struct {" \ +" <no data fields>" \ "" \ -" /* total size (bytes): 1 */" \ -" } empty;" \ -"/* XXX 3-byte hole */" \ -"/* 4 | 4 */ int an_int;" \ +" /* total size (bytes): 1 */" \ +" } empty;" \ +"/* XXX 3-byte hole */" \ +"/* 4 | 4 */ int an_int;" \ "" \ -" /* total size (bytes): 8 */" \ -" \}"]] +" /* total size (bytes): 8 */" \ +" \}"]] + +with_test_prefix "with_hex_default" { + # Test setting default display to hex + send_gdb "set print type hex on\n" + gdb_test "show print type hex" \ + "Display of struct members offsets and sizes in hexadecimal is on" + + # test "ptype /o" is now equivalent to "ptype /ox" + gdb_test "ptype /o struct abc" \ + [string_to_regexp [multi_line \ + "/* offset | size */ type = struct abc \{" \ + " public:" \ + "/* 0x0008 | 0x0008 */ void *field1;" \ + "/* 0x0010: 0x0 | 0x0004 */ unsigned int field2 : 1;" \ + "/* XXX 7-bit hole */" \ + "/* XXX 3-byte hole */" \ + "/* 0x0014 | 0x0004 */ int field3;" \ + "/* 0x0018 | 0x0001 */ signed char field4;" \ + "/* XXX 7-byte hole */" \ + "/* 0x0020 | 0x0008 */ uint64_t field5;" \ + "/* 0x0028 | 0x0008 */ union \{" \ + "/* 0x0008 */ void *field6;" \ + "/* 0x0004 */ int field7;" \ + "" \ + " /* total size (bytes): 8 */" \ + " \} field8;" \ + "/* 0x0030 | 0x0002 */ my_int_type field9;" \ + "/* XXX 6-byte padding */" \ + "" \ + " /* total size (bytes): 56 */" \ + " \}"]] + + gdb_test "ptype /od struct abc" \ + [string_to_regexp [multi_line \ + "/* offset | size */ type = struct abc \{" \ + " public:" \ + "/* 8 | 8 */ void *field1;" \ + "/* 16: 0 | 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 | 2 */ my_int_type field9;" \ + "/* XXX 6-byte padding */" \ + "" \ + " /* total size (bytes): 56 */" \ + " \}"]] + + # restore + send_gdb "set print type hex off\n" +} diff --git a/gdb/testsuite/gdb.rust/simple.exp b/gdb/testsuite/gdb.rust/simple.exp index 1588e15..cf9d400 100644 --- a/gdb/testsuite/gdb.rust/simple.exp +++ b/gdb/testsuite/gdb.rust/simple.exp @@ -364,12 +364,12 @@ gdb_test "print parametrized" \ " = simple::ParametrizedStruct<i32> \\{next: simple::ParametrizedEnum<\[a-z:\]*Box<simple::ParametrizedStruct<i32>.*>>::Val\\{val: $hex\\}, value: 0\\}" gdb_test_sequence "ptype/o SimpleLayout" "" { - "/\\* offset | size \\*/ type = struct simple::SimpleLayout {" - "/\\* 0 | 2 \\*/ f1: u16," - "/\\* 2 | 2 \\*/ f2: u16," + "/\\* offset | size \\*/ type = struct simple::SimpleLayout {" + "/\\* 0 | 2 \\*/ f1: u16," + "/\\* 2 | 2 \\*/ f2: u16," "" - " /\\* total size \\(bytes\\): 4 \\*/" - " }" + " /\\* total size \\(bytes\\): 4 \\*/" + " }" } gdb_test "print nonzero_offset" " = simple::EnumWithNonzeroOffset {a: core::option::Option<u8>::Some\\(1\\), b: core::option::Option<u8>::None}" diff --git a/gdb/testsuite/gdb.rust/union.exp b/gdb/testsuite/gdb.rust/union.exp index 3a2e6bc..ce59a36 100644 --- a/gdb/testsuite/gdb.rust/union.exp +++ b/gdb/testsuite/gdb.rust/union.exp @@ -34,12 +34,12 @@ if {![runto ${srcfile}:$line]} { gdb_test "print u" " = union::Union {f1: -1, f2: 255}" gdb_test_sequence "ptype/o Union" "" { - "/\\* offset | size \\*/ type = union union::Union {" - "/\\* 1 \\*/ f1: i8," - "/\\* 1 \\*/ f2: u8," + "/\\* offset | size \\*/ type = union union::Union {" + "/\\* 1 \\*/ f1: i8," + "/\\* 1 \\*/ f2: u8," "" - " /\\* total size \\(bytes\\): 1 \\*/" - " }" + " /\\* total size \\(bytes\\): 1 \\*/" + " }" } gdb_test "print u2" " = union::Union2 {name: \\\[1\\\]}" diff --git a/gdb/typeprint.c b/gdb/typeprint.c index 1af1d17..eb47d91 100644 --- a/gdb/typeprint.c +++ b/gdb/typeprint.c @@ -44,6 +44,7 @@ const struct type_print_options type_print_raw_options = 1, /* print_methods */ 1, /* print_typedefs */ 0, /* print_offsets */ + 0, /* print_in_hex */ 0, /* print_nested_type_limit */ NULL, /* local_typedefs */ NULL, /* global_table */ @@ -58,6 +59,7 @@ static struct type_print_options default_ptype_flags = 1, /* print_methods */ 1, /* print_typedefs */ 0, /* print_offsets */ + 0, /* print_in_hex */ 0, /* print_nested_type_limit */ NULL, /* local_typedefs */ NULL, /* global_table */ @@ -68,8 +70,15 @@ static struct type_print_options default_ptype_flags = /* See typeprint.h. */ -const int print_offset_data::indentation = 23; +const int print_offset_data::indentation = 27; +/* See typeprint.h. */ + +print_offset_data::print_offset_data (const struct type_print_options *flags) +{ + if (flags != nullptr) + print_in_hex = flags->print_in_hex; +} /* See typeprint.h. */ @@ -95,11 +104,11 @@ print_offset_data::maybe_print_hole (struct ui_file *stream, unsigned int hole_bit = hole % TARGET_CHAR_BIT; if (hole_bit > 0) - fprintf_filtered (stream, "/* XXX %2u-bit %s */\n", hole_bit, + fprintf_filtered (stream, "/* XXX %2u-bit %-7s */\n", hole_bit, for_what); if (hole_byte > 0) - fprintf_filtered (stream, "/* XXX %2u-byte %s */\n", hole_byte, + fprintf_filtered (stream, "/* XXX %2u-byte %-7s */\n", hole_byte, for_what); } } @@ -121,8 +130,10 @@ print_offset_data::update (struct type *type, unsigned int field_idx, { /* Since union fields don't have the concept of offsets, we just print their sizes. */ - fprintf_filtered (stream, "/* %4s */", - pulongest (TYPE_LENGTH (ftype))); + fprintf_filtered (stream, "/* %6s */", + (print_in_hex ? + hex_string_custom (TYPE_LENGTH (ftype), 4) : + pulongest (TYPE_LENGTH (ftype)))); return; } @@ -140,20 +151,23 @@ print_offset_data::update (struct type *type, unsigned int field_idx, unsigned real_bitpos = bitpos + offset_bitpos; - fprintf_filtered (stream, "/* %4u:%2u", real_bitpos / TARGET_CHAR_BIT, + fprintf_filtered (stream, + (print_in_hex ? "/* 0x%04x: 0x%x" : "/* %6u:%2u "), + real_bitpos / TARGET_CHAR_BIT, real_bitpos % TARGET_CHAR_BIT); } else { /* The position of the field, relative to the beginning of the struct. */ - fprintf_filtered (stream, "/* %4u", + fprintf_filtered (stream, (print_in_hex ? "/* 0x%04x" : "/* %6u"), (bitpos + offset_bitpos) / TARGET_CHAR_BIT); - fprintf_filtered (stream, " "); + fprintf_filtered (stream, " "); } - fprintf_filtered (stream, " | %4u */", fieldsize_byte); + fprintf_filtered (stream, (print_in_hex ? " | 0x%04x */" : " | %6u */"), + fieldsize_byte); end_bitpos = bitpos + fieldsize_bit; } @@ -468,6 +482,12 @@ whatis_exp (const char *exp, int show) } break; } + case 'x': + flags.print_in_hex = 1; + break; + case 'd': + flags.print_in_hex = 0; + break; default: error (_("unrecognized flag '%c'"), *exp); } @@ -528,7 +548,7 @@ whatis_exp (const char *exp, int show) if (flags.print_offsets && (type->code () == TYPE_CODE_STRUCT || type->code () == TYPE_CODE_UNION)) - fprintf_filtered (gdb_stdout, "/* offset | size */ "); + fprintf_filtered (gdb_stdout, "/* offset | size */ "); printf_filtered ("type = "); @@ -763,6 +783,35 @@ show_print_type_nested_types (struct ui_file *file, int from_tty, } } +/* When printing structs, offsets and sizes of members can be displayed using + decimal notation or hexadecimal notation. By default, Decimal notation is + used. */ + +static bool print_offsets_and_sizes_in_hex = false; + +/* Set the flags that instructs if sizes and offsets of struct members are + displayed in hexadecimal or decimal notation. */ + +static void +set_print_offsets_and_sizes_in_hex (const char *args, + int from_tty, struct cmd_list_element *c) +{ + default_ptype_flags.print_in_hex = print_offsets_and_sizes_in_hex; +} + +/* Display whether struct members sizes and offsets are printed + using decimal or hexadecimal notation. */ + +static void +show_print_offsets_and_sizes_in_hex (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + fprintf_filtered (file, _("\ +Display of struct members offsets and sizes in hexadecimal is %s\n"), + value); +} + void _initialize_typeprint (); void _initialize_typeprint () @@ -784,7 +833,11 @@ Available FLAGS are:\n\ /M print methods defined in a class\n\ /t do not print typedefs defined in a class\n\ /T print typedefs defined in a class\n\ - /o print offsets and sizes of fields in a struct (like pahole)")); + /o print offsets and sizes of fields in a struct (like pahole)\n\ + /x use hexadecimal notation when displaying sizes and offsets\n\ + of struct members\n\ + /d use decimal notation when displaying sizes and offsets\n\ + of struct members ")); set_cmd_completer (c, expression_completer); c = add_com ("whatis", class_vars, whatis_command, @@ -825,6 +878,14 @@ Show the number of recursive nested type definitions to print."), NULL, set_print_type_nested_types, show_print_type_nested_types, &setprinttypelist, &showprinttypelist); + + add_setshow_boolean_cmd ("hex", no_class, &print_offsets_and_sizes_in_hex, + _("\ +Set printing of struct members sizes and offsets using hex notation."), _("\ +Show whether sizes and offsets of struct members are printed using hex \ +notation."), nullptr, set_print_offsets_and_sizes_in_hex, + show_print_offsets_and_sizes_in_hex, + &setprinttypelist, &showprinttypelist); } /* Print <not allocated> status to stream STREAM. */ diff --git a/gdb/typeprint.h b/gdb/typeprint.h index 75204f6..86e7813 100644 --- a/gdb/typeprint.h +++ b/gdb/typeprint.h @@ -40,6 +40,9 @@ struct type_print_options /* True means to print offsets, a la 'pahole'. */ unsigned int print_offsets : 1; + /* True means to print offsets in hex, otherwise use decimal. */ + unsigned int print_in_hex : 1; + /* The number of nested type definitions to print. -1 == all. */ int print_nested_type_limit; @@ -58,6 +61,10 @@ struct type_print_options struct print_offset_data { + /* Indicate if the offset an d size fields should be printed in decimal + (default) or hexadecimal. */ + bool print_in_hex = false; + /* The offset to be applied to bitpos when PRINT_OFFSETS is true. This is needed for when we are printing nested structs and want to make sure that the printed offset for each field carries over @@ -92,6 +99,8 @@ struct print_offset_data certain field. */ static const int indentation; + explicit print_offset_data (const struct type_print_options *flags); + private: /* Helper function for ptype/o implementation that prints |