[v3,2/2,PR,gdb/22640] ptype: add option to use hexadecimal notation

Message ID 20210423222838.41119-3-lsix@lancelotsix.com
State New
Headers show
Series
  • Have ptype support hex display of offsets and sizes
Related show

Commit Message

Simon Marchi via Gdb-patches April 23, 2021, 10:28 p.m.
This commit adds a flag to the ptype command in order to print the
offsets and sizes of struct members using the hexadecimal notation.  The
'x' flag ensures use of the hexadecimal notation while the 'd' flag
ensures use of the decimal notation.  The default is to use decimal
notation.

Before this patch, gdb only uses decimal notation, as pointed out in PR
gdb/22640.

Here is an example of this new behavior with hex output turned on:

    (gdb) ptype /ox struct type_print_options
    /* offset      |    size */  type = struct type_print_options {
    /* 0x0000: 0x0 |  0x0004 */    unsigned int raw : 1;
    /* 0x0000: 0x1 |  0x0004 */    unsigned int print_methods : 1;
    /* 0x0000: 0x2 |  0x0004 */    unsigned int print_typedefs : 1;
    /* 0x0000: 0x3 |  0x0004 */    unsigned int print_offsets : 1;
    /* 0x0000: 0x4 |  0x0004 */    unsigned int print_in_hex : 1;
    /* XXX  3-bit hole       */
    /* XXX  3-byte hole      */
    /* 0x0004      |  0x0004 */    int print_nested_type_limit;
    /* 0x0008      |  0x0008 */    typedef_hash_table *local_typedefs;
    /* 0x0010      |  0x0008 */    typedef_hash_table *global_typedefs;
    /* 0x0018      |  0x0008 */    ext_lang_type_printers *global_printers;

                                   /* total size (bytes):   32 */
                                 }

This patch also adds the 'set print type hex' and 'show print type hex'
commands in order to set and inspect the default behavior regarding the
use of decimal or hexadecimal notation when printing struct sizes and
offsets.

Tested using on x86_64.

---

Since V2:

	- Fix conflicts with changes done in 'Fix ptype/o bug with "<no
	data fields>"' (432ce4cf6800a3693656fde1306d83ce767e2b2a).
	- Fix coding style according to review.
	- Update documentation part according to review.

Since V1:

	- Use more horizontal space to allow 4 hexadecimal digits, or 6
	decimal digits.
	- Bit offsets are also printed in hex.  Arguably this is not necessary
	since this value is lower than TARGET_CHAR_BIT, so for all targets I
	can think of decimal and hexadecimal notations are identical (except
	for the 0x prefix).
	- Use 'd' as flag to force use of decimal display instead of 'X'.

gdb/ChangeLog:

	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.

gdb/doc/ChangeLog:

	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.

gdb/testsuite/ChangeLog:

	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.
---
 gdb/NEWS                                 |  12 +
 gdb/c-typeprint.c                        |   8 +-
 gdb/doc/gdb.texinfo                      | 113 +++--
 gdb/rust-lang.c                          |   2 +-
 gdb/testsuite/gdb.base/ptype-offsets.exp | 562 ++++++++++++++---------
 gdb/testsuite/gdb.rust/simple.exp        |  10 +-
 gdb/testsuite/gdb.rust/union.exp         |  10 +-
 gdb/typeprint.c                          |  83 +++-
 gdb/typeprint.h                          |   9 +
 9 files changed, 514 insertions(+), 295 deletions(-)

-- 
2.31.1

Comments

Simon Marchi via Gdb-patches April 24, 2021, 6:15 a.m. | #1
> Date: Fri, 23 Apr 2021 23:28:38 +0100

> From: Lancelot SIX via Gdb-patches <gdb-patches@sourceware.org>

> Cc: Lancelot SIX <lsix@lancelotsix.com>

> 

> gdb/ChangeLog:

> 

> 	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.

> 

> gdb/doc/ChangeLog:

> 

> 	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.

> 

> gdb/testsuite/ChangeLog:

> 

> 	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.


Thanks, the documentation parts are OK.

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index faccf40dd41..1cdf19c09a0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -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 72616a59af0..0502d31eff9 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/gdb.texinfo b/gdb/doc/gdb.texinfo
index fd04aeee8fc..a068de6c95b 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 a57ee988668..8c4d209b07a 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/gdb.base/ptype-offsets.exp b/gdb/testsuite/gdb.base/ptype-offsets.exp
index 0a0bbc87062..cc017ad7909 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 1588e155165..cf9d400a092 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 3a2e6bc1176..ce59a364b0c 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 1af1d173a61..eb47d9129f9 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 75204f6a5d5..86e781378f9 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