Adjust byte order variable display/change if DW_AT_endianity is present.

Message ID VI1PR05MB5726CD7B5A1AA8DA2DE226AE9C710@VI1PR05MB5726.eurprd05.prod.outlook.com
State New, archived
Headers

Commit Message

Peeter Joot Nov. 14, 2019, 5:15 p.m. UTC
  - Rationale:
It is possible for compilers to indicate the desired byte order
interpretation of scalar variables using the DWARF attribute:
   DW_AT_endianity

A type flagged with this variable would typically use one of:
   DW_END_big
   DW_END_little
which instructs the debugger what the desired byte order interpretation
of the variable should be.

The GCC compiler (as of V6) has a mechanism for setting the desired byte
ordering of the fields within a structure or union.  For, example, on a
little endian target, a structure declared as:
   struct big {
       int v;
       short a[4];
   } __attribute__( ( scalar_storage_order( "big-endian" ) ) );
could be used to ensure all the structure members have a big-endian
interpretation (the compiler would automatically insert byte swap
instructions before and after respective store and load instructions).

- To reproduce
GCC V8+ is required to correctly emit DW_AT_endianity DWARF attributes
in all situations when the scalar_storage_order attribute is used.

A fix for (dwarf endianity instrumentation) for GCC V6-V7 can be found
in the URL field of the following PR:
   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82509

- Test-case:
A new test case (testsuite/gdb.base/endianity.*) is included with this
patch.

Manual testing for mixed endianity code has also been done with GCC V8.
See:
   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82509#c4

- Observed vs. expected:

Without this change, using scalar_storage_order that doesn't match the
target, such as

struct otherendian
{
  int v;
} __attribute__( ( scalar_storage_order( "big-endian" ) ) );

would behave like the following on a little endian target:

   Breakpoint 1 at 0x401135: file endianity.c, line 41.
   (gdb) run
   Starting program: /home/pjoot/freeware/t/a.out
   Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64

   Breakpoint 1, main () at endianity.c:41
   41        struct otherendian o = {3};
   (gdb) n
   43        do_nothing (&o); /* START */
   (gdb) p o
   $1 = {v = 50331648}
   (gdb) p /x
   $2 = {v = 0x3000000}

whereas with this gdb enhancement we can access the variable with the user
specified endianity:

   Breakpoint 1, main () at endianity.c:41
   41        struct otherendian o = {3};
   (gdb) p o
   $1 = {v = 0}
   (gdb) n
   43        do_nothing (&o); /* START */
   (gdb) p o
   $2 = {v = 3}
   (gdb) p o.v = 4
   $3 = 4
   (gdb) p o.v
   $4 = 4
   (gdb) x/4xb &o.v
   0x7fffffffd90c: 0x00    0x00    0x00    0x04

(observe that the 4 byte int variable has a big endian representation in the
 hex dump.)

- FSF copyright Assignment

I am contributing on behalf of my employer, LzLabs GbmH.  The FSF attribution documentation for binutils and gdb are both complete and signed back.

- Changelogs:

gdb/ChangeLog:

2019-11-14  Peeter Joot  <peeter.joot@lzlabs.com>

Byte reverse display of variables with DW_END_big, DW_END_little
(DW_AT_endianity) dwarf attributes if different than the native
byte order.
* ada-lang.c (ada_value_binop):
Use type_byte_order instead of gdbarch_byte_order.
* ada-valprint.c (printstr):
(ada_val_print_string):
Use type_byte_order instead of gdbarch_byte_order.
* c-lang.c (c_get_string):
Use type_byte_order instead of gdbarch_byte_order.
* c-valprint.c (c_val_print_array):
Use type_byte_order instead of gdbarch_byte_order.
* cp-valprint.c (cp_print_class_member):
Use type_byte_order instead of gdbarch_byte_order.
* dwarf2loc.c (rw_pieced_value):
Use type_byte_order instead of gdbarch_byte_order.
* dwarf2read.c (read_base_type): Handle DW_END_big,
DW_END_little
* f-lang.c (f_get_encoding):
Use type_byte_order instead of gdbarch_byte_order.
* findvar.c (default_read_var_value):
Use type_byte_order instead of gdbarch_byte_order.
* gdbtypes.c (check_types_equal):
Require matching TYPE_ENDIANITY_BIG, and
TYPE_ENDIANITY_LITTLE if set.
(recursive_dump_type): Print TYPE_ENDIANITY_BIG,
and TYPE_ENDIANITY_LITTLE if set.
(type_byte_order): new function.
* gdbtypes.h (TYPE_ENDIANITY_BIG, TYPE_ENDIANITY_LITTLE): New macro.
(struct main_type) <flag_endianity_big, flag_endianity_little>:
New field.
(type_byte_order): New function.
* infcmd.c (default_print_one_register_info):
Use type_byte_order instead of gdbarch_byte_order.
* p-lang.c (pascal_printstr):
Use type_byte_order instead of gdbarch_byte_order.
* p-valprint.c (pascal_val_print):
Use type_byte_order instead of gdbarch_byte_order.
* printcmd.c (print_scalar_formatted):
Use type_byte_order instead of gdbarch_byte_order.
* solib-darwin.c (darwin_current_sos):
Use type_byte_order instead of gdbarch_byte_order.
* solib-svr4.c (solib_svr4_r_ldsomap):
Use type_byte_order instead of gdbarch_byte_order.
* stap-probe.c (stap_modify_semaphore):
Use type_byte_order instead of gdbarch_byte_order.
* target-float.c (target_float_same_format_p):
Use type_byte_order instead of gdbarch_byte_order.
* valarith.c (scalar_binop):
Use type_byte_order instead of gdbarch_byte_order.
* valops.c (value_cast):
Use type_byte_order instead of gdbarch_byte_order.
* valprint.c (generic_emit_char):
(generic_printstr):
(val_print_string):
Use type_byte_order instead of gdbarch_byte_order.
* value.c (unpack_long):
(unpack_bits_as_long):
(unpack_value_bitfield):
(modify_field):
(pack_long):
(pack_unsigned_long):
Use type_byte_order instead of gdbarch_byte_order.

gdb/testsuite/ChangeLog:

2019-11-14  Peeter Joot  <peeter.joot@lzlabs.com>

* gdb.base/endianity.c: New test.
* gdb.base/endianity.exp: New file.
---
 gdb/ada-lang.c                       |  2 +-
 gdb/ada-valprint.c                   |  4 ++--
 gdb/c-lang.c                         |  2 +-
 gdb/c-valprint.c                     |  3 +--
 gdb/cp-valprint.c                    |  2 +-
 gdb/dwarf2loc.c                      |  2 +-
 gdb/dwarf2read.c                     | 18 +++++++++++----
 gdb/f-lang.c                         |  2 +-
 gdb/findvar.c                        |  2 +-
 gdb/gdbtypes.c                       | 21 +++++++++++++++++
 gdb/gdbtypes.h                       | 20 ++++++++++++++++
 gdb/infcmd.c                         |  2 +-
 gdb/p-lang.c                         |  2 +-
 gdb/p-valprint.c                     |  2 +-
 gdb/printcmd.c                       |  2 +-
 gdb/solib-darwin.c                   |  2 +-
 gdb/solib-svr4.c                     |  2 +-
 gdb/stap-probe.c                     |  7 +++---
 gdb/target-float.c                   |  6 ++---
 gdb/testsuite/gdb.base/endianity.c   | 44 ++++++++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.base/endianity.exp | 38 +++++++++++++++++++++++++++++++
 gdb/valarith.c                       |  8 +++----
 gdb/valops.c                         |  2 +-
 gdb/valprint.c                       |  6 ++---
 gdb/value.c                          | 12 +++++-----
 25 files changed, 171 insertions(+), 42 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/endianity.c
 create mode 100644 gdb/testsuite/gdb.base/endianity.exp

--
2.9.1.200.gb1ec08f
  

Comments

Tom Tromey Nov. 14, 2019, 8:37 p.m. UTC | #1
>>>>> "Peeter" == Peeter Joot <peeter.joot@lzlabs.com> writes:

Peeter> - Rationale:
Peeter> It is possible for compilers to indicate the desired byte order
Peeter> interpretation of scalar variables using the DWARF attribute:
Peeter>    DW_AT_endianity

Thank you for the patch.  As you know, I've been eagerly waiting for
this!

This looks basically good to me.

Peeter> --- a/gdb/ada-lang.c
Peeter> +++ b/gdb/ada-lang.c
Peeter> @@ -9678,7 +9678,7 @@ ada_value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
Peeter>    val = allocate_value (type1);
Peeter>    store_unsigned_integer (value_contents_raw (val),
Peeter>                            TYPE_LENGTH (value_type (val)),
Peeter> -  gdbarch_byte_order (get_type_arch (type1)), v);
Peeter> +  type_byte_order (type1), v);

There seems to have been a problem with the mail, because this line is
indented differently in the original source.

You can use gerrit now, instead, which should circumvent problems like
this:

    https://sourceware.org/gdb/wiki/Gerrit

"git send-email" also has been reliable for me.


One over-arching question I had was whether this patch attempts to
update every spot currently saying

    gdbarch_byte_order (get_type_arch (type1))

If not, what were the criteria?

If so, I noticed a spot in ada-lang.c that was missed, presumably
because it was split up:

    static CORE_ADDR
    value_pointer (struct value *value, struct type *type)
    {
      struct gdbarch *gdbarch = get_type_arch (type);
[...]
      addr = extract_unsigned_integer (buf, len, gdbarch_byte_order (gdbarch));


Peeter> +  unsigned int flag_endianity_big : 1;
Peeter> +  unsigned int flag_endianity_little : 1;

Could we use just a single bit and simply record whether or not the type
has the same endianity as its architecture?

It's not so much a matter of space (we've got spare bits available
there), but rather if there are two fields, then one has to wonder what
it means if they are both set, etc.

Peeter> +# Copyright 2017 Free Software Foundation, Inc.

This date and the one in the test case .c file should be updated, I
think.

Tom
  
Peeter Joot Nov. 14, 2019, 10:55 p.m. UTC | #2
> One over-arching question I had was whether this patch attempts to
> update every spot currently saying

I'll re-review the remaining byte ordering checks.  I think that I was pretty thorough originally, and if I missed stuff in this iteration, it's probably mostly because the code changed too much since I originally prepared the patch.  I've clearly changed enough to make the desired operations work in my own testing (and the gdb unit test), but I think it would be best to be systematic.

Peeter

> Peeter> +  unsigned int flag_endianity_big : 1;
> Peeter> +  unsigned int flag_endianity_little : 1;
> Could we use just a single bit and simply record whether or not the type
> has the same endianity as its architecture?

I'll review what I did -- what you describe sounds reasonable.

> This date and the one in the test case .c file should be updated, I think.

Okay, will do.

> There seems to have been a problem with the mail, because this line is
indented differently in the original source.

After making the changes above, I'll resend with the git format-patch file as an attachment instead of inline.

Peeter
  
Tom Tromey Nov. 21, 2019, 6:41 p.m. UTC | #3
>>>>> "Peeter" == Peeter Joot <peeter.joot@lzlabs.com> writes:

Peeter> Here's a revised patch.  Changes from the previous version:
[...]

Peeter> The testsuite still runs cleanly (diff attached), as did my
Peeter> manual testing (w/ DW_END_* code compiled with gcc-9.2 and our
Peeter> in-house PL/I compiler).

PL/I -- wow.

I read this patch and it looks ok to me.  I am checking it in.

Thank you very much for doing this.

If you plan to submit more gdb patches, contact me off-list and I will
set you up with write-after-commit access.

Tom
  

Patch

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 2935df5..cfe950a 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -9678,7 +9678,7 @@  ada_value_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   val = allocate_value (type1);
   store_unsigned_integer (value_contents_raw (val),
                           TYPE_LENGTH (value_type (val)),
-  gdbarch_byte_order (get_type_arch (type1)), v);
+  type_byte_order (type1), v);
   return val;
 }

diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
index 5ab0365..4bb9247 100644
--- a/gdb/ada-valprint.c
+++ b/gdb/ada-valprint.c
@@ -476,7 +476,7 @@  printstr (struct ui_file *stream, struct type *elttype, const gdb_byte *string,
   unsigned int length, int force_ellipses, int type_len,
   const struct value_print_options *options)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (elttype));
+  enum bfd_endian byte_order = type_byte_order (elttype);
   unsigned int i;
   unsigned int things_printed = 0;
   int in_quotes = 0;
@@ -719,7 +719,7 @@  ada_val_print_string (struct type *type, const gdb_byte *valaddr,
       struct value *original_value,
       const struct value_print_options *options)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  enum bfd_endian byte_order = type_byte_order (type);
   struct type *elttype = TYPE_TARGET_TYPE (type);
   unsigned int eltlen;
   unsigned int len;
diff --git a/gdb/c-lang.c b/gdb/c-lang.c
index 74e3f73..1de44f7 100644
--- a/gdb/c-lang.c
+++ b/gdb/c-lang.c
@@ -245,7 +245,7 @@  c_get_string (struct value *value, gdb::unique_xmalloc_ptr<gdb_byte> *buffer,
   struct type *element_type = TYPE_TARGET_TYPE (type);
   int req_length = *length;
   enum bfd_endian byte_order
-    = gdbarch_byte_order (get_type_arch (type));
+    = type_byte_order (type);

   if (element_type == NULL)
     goto error;
diff --git a/gdb/c-valprint.c b/gdb/c-valprint.c
index c4306f1..58675f6 100644
--- a/gdb/c-valprint.c
+++ b/gdb/c-valprint.c
@@ -247,8 +247,7 @@  c_val_print_array (struct type *type, const gdb_byte *valaddr,
     {
       LONGEST low_bound, high_bound;
       int eltlen, len;
-      struct gdbarch *gdbarch = get_type_arch (type);
-      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+      enum bfd_endian byte_order = type_byte_order (type);
       unsigned int i = 0; /* Number of characters printed.  */

       if (!get_array_bounds (type, &low_bound, &high_bound))
diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 04be4dc..e445d42 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -740,7 +740,7 @@  void
 cp_print_class_member (const gdb_byte *valaddr, struct type *type,
        struct ui_file *stream, const char *prefix)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  enum bfd_endian byte_order = type_byte_order (type);

   /* VAL is a byte offset into the structure type SELF_TYPE.
      Find the name of the field for that offset and
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index c8ba029..e25ee66 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -1601,7 +1601,7 @@  rw_pieced_value (struct value *v, struct value *from)
       bits_to_skip += (8 * value_offset (value_parent (v))
        + value_bitpos (v));
       if (from != NULL
-  && (gdbarch_byte_order (get_type_arch (value_type (from)))
+  && (type_byte_order (value_type (from))
       == BFD_ENDIAN_BIG))
  {
   /* Use the least significant bits of FROM.  */
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index bbfa442..711a8d3 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -17661,23 +17661,23 @@  read_base_type (struct die_info *die, struct dwarf2_cu *cu)
   struct type *type;
   struct attribute *attr;
   int encoding = 0, bits = 0;
+  int endianity = 0;
   const char *name;

   attr = dwarf2_attr (die, DW_AT_encoding, cu);
   if (attr)
-    {
       encoding = DW_UNSND (attr);
-    }
   attr = dwarf2_attr (die, DW_AT_byte_size, cu);
   if (attr)
-    {
       bits = DW_UNSND (attr) * TARGET_CHAR_BIT;
-    }
   name = dwarf2_name (die, cu);
   if (!name)
     {
       complaint (_("DW_AT_name missing from DW_TAG_base_type"));
     }
+  attr = dwarf2_attr (die, DW_AT_endianity, cu);
+  if (attr)
+    endianity = DW_UNSND (attr);

   switch (encoding)
     {
@@ -17757,6 +17757,16 @@  read_base_type (struct die_info *die, struct dwarf2_cu *cu)

   maybe_set_alignment (cu, die, type);

+  switch (endianity)
+    {
+      case DW_END_big:
+        TYPE_ENDIANITY_BIG (type) = 1;
+        break;
+      case DW_END_little:
+        TYPE_ENDIANITY_LITTLE (type) = 1;
+        break;
+    }
+
   return set_die_type (die, type, cu);
 }

diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 7f241c6..fd4ad0f 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -59,7 +59,7 @@  f_get_encoding (struct type *type)
       encoding = target_charset (get_type_arch (type));
       break;
     case 4:
-      if (gdbarch_byte_order (get_type_arch (type)) == BFD_ENDIAN_BIG)
+      if (type_byte_order (type) == BFD_ENDIAN_BIG)
  encoding = "UTF-32BE";
       else
  encoding = "UTF-32LE";
diff --git a/gdb/findvar.c b/gdb/findvar.c
index bbfd689..19ce762 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -620,7 +620,7 @@  default_read_var_value (struct symbol *var, const struct block *var_block,
       /* Put the constant back in target format. */
       v = allocate_value (type);
       store_signed_integer (value_contents_raw (v), TYPE_LENGTH (type),
-    gdbarch_byte_order (get_type_arch (type)),
+    type_byte_order (type),
     (LONGEST) SYMBOL_VALUE (var));
       VALUE_LVAL (v) = not_lval;
       return v;
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index fd1c765..0a5c07f 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -3616,6 +3616,8 @@  check_types_equal (struct type *type1, struct type *type2,
       || TYPE_LENGTH (type1) != TYPE_LENGTH (type2)
       || TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)
       || TYPE_NOSIGN (type1) != TYPE_NOSIGN (type2)
+      || TYPE_ENDIANITY_BIG (type1) != TYPE_ENDIANITY_BIG (type2)
+      || TYPE_ENDIANITY_LITTLE (type1) != TYPE_ENDIANITY_LITTLE (type2)
       || TYPE_VARARGS (type1) != TYPE_VARARGS (type2)
       || TYPE_VECTOR (type1) != TYPE_VECTOR (type2)
       || TYPE_NOTTEXT (type1) != TYPE_NOTTEXT (type2)
@@ -4669,6 +4671,14 @@  recursive_dump_type (struct type *type, int spaces)
     {
       puts_filtered (" TYPE_NOSIGN");
     }
+  if (TYPE_ENDIANITY_BIG (type))
+    {
+      puts_filtered (" TYPE_ENDIANITY_BIG");
+    }
+  if (TYPE_ENDIANITY_LITTLE (type))
+    {
+      puts_filtered (" TYPE_ENDIANITY_LITTLE");
+    }
   if (TYPE_STUB (type))
     {
       puts_filtered (" TYPE_STUB");
@@ -5617,3 +5627,14 @@  _initialize_gdbtypes (void)
    show_strict_type_checking,
    &setchecklist, &showchecklist);
 }
+
+/* See gdbtypes.h.  */
+enum bfd_endian
+type_byte_order (const struct type *type)
+{
+  if (TYPE_ENDIANITY_BIG (type))
+    return BFD_ENDIAN_BIG;
+  else if (TYPE_ENDIANITY_LITTLE (type))
+    return BFD_ENDIAN_LITTLE;
+  return gdbarch_byte_order (get_type_arch (type));
+}
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 6d6ff59..951dcee 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -219,6 +219,18 @@  DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags);

 #define TYPE_NOSIGN(t) (TYPE_MAIN_TYPE (t)->flag_nosign)

+/* * Mixed endian architectures can supply dwarf instrumentation
+   that indicates the desired endian interpretation of the variable.
+   This indicates that the interpretation should be big-endian
+   even if the cpu is running in little endian mode.  */
+
+#define TYPE_ENDIANITY_BIG(t) (TYPE_MAIN_TYPE (t)->flag_endianity_big)
+
+/* * The type has a little endian interpretation even if the cpu
+   is running in big endian mode.  */
+
+#define TYPE_ENDIANITY_LITTLE(t) (TYPE_MAIN_TYPE (t)->flag_endianity_little)
+
 /* * This appears in a type's flags word if it is a stub type (e.g.,
    if someone referenced a type that wasn't defined in a source file
    via (struct sir_not_appearing_in_this_film *)).  */
@@ -701,6 +713,8 @@  struct main_type
   unsigned int flag_gnu_ifunc : 1;
   unsigned int flag_fixed_instance : 1;
   unsigned int flag_objfile_owned : 1;
+  unsigned int flag_endianity_big : 1;
+  unsigned int flag_endianity_little : 1;

   /* * True if this type was declared with "class" rather than
      "struct".  */
@@ -2146,6 +2160,12 @@  extern int type_not_allocated (const struct type *type);

 extern int type_not_associated (const struct type *type);

+/* * When the type includes explicit byte ordering, return that.
+   Otherwise, the byte ordering from gdbarch_byte_order for
+   get_type_arch is returned.  */
+
+extern enum bfd_endian type_byte_order (const struct type *type);
+
 /* A flag to enable printing of debugging information of C++
    overloading.  */

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 5ca9933..eb18efa 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -2216,7 +2216,7 @@  default_print_one_register_info (struct ui_file *file,
     {
       struct value_print_options opts;
       const gdb_byte *valaddr = value_contents_for_printing (val);
-      enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (regtype));
+      enum bfd_endian byte_order = type_byte_order (regtype);

       get_user_print_options (&opts);
       opts.deref_ref = 1;
diff --git a/gdb/p-lang.c b/gdb/p-lang.c
index 0cf1c6c..33cb6e6 100644
--- a/gdb/p-lang.c
+++ b/gdb/p-lang.c
@@ -230,7 +230,7 @@  pascal_printstr (struct ui_file *stream, struct type *type,
  const char *encoding, int force_ellipses,
  const struct value_print_options *options)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  enum bfd_endian byte_order = type_byte_order (type);
   unsigned int i;
   unsigned int things_printed = 0;
   int in_quotes = 0;
diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c
index 10612f3..c465d14 100644
--- a/gdb/p-valprint.c
+++ b/gdb/p-valprint.c
@@ -67,7 +67,7 @@  pascal_val_print (struct type *type,
   const struct value_print_options *options)
 {
   struct gdbarch *gdbarch = get_type_arch (type);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order = type_byte_order (type);
   unsigned int i = 0; /* Number of characters printed */
   unsigned len;
   struct type *elttype;
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 323a5d0..0251d46 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -356,7 +356,7 @@  print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
 {
   struct gdbarch *gdbarch = get_type_arch (type);
   unsigned int len = TYPE_LENGTH (type);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order = type_byte_order (type);

   /* String printing should go through val_print_scalar_formatted.  */
   gdb_assert (options->format != 's');
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index 286e385..969bfd5 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -223,7 +223,7 @@  static struct so_list *
 darwin_current_sos (void)
 {
   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
-  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+  enum bfd_endian byte_order = type_byte_order (ptr_type);
   int ptr_len = TYPE_LENGTH (ptr_type);
   unsigned int image_info_size;
   struct so_list *head = NULL;
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 27299ff..de76557 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -897,7 +897,7 @@  solib_svr4_r_ldsomap (struct svr4_info *info)
 {
   struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
-  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+  enum bfd_endian byte_order = type_byte_order (ptr_type);
   ULONGEST version = 0;

   try
diff --git a/gdb/stap-probe.c b/gdb/stap-probe.c
index ea206cb..ba92779 100644
--- a/gdb/stap-probe.c
+++ b/gdb/stap-probe.c
@@ -1435,8 +1435,8 @@  stap_modify_semaphore (CORE_ADDR address, int set, struct gdbarch *gdbarch)
       return;
     }

-  value = extract_unsigned_integer (bytes, TYPE_LENGTH (type),
-    gdbarch_byte_order (gdbarch));
+  enum bfd_endian byte_order = type_byte_order (type);
+  value = extract_unsigned_integer (bytes, TYPE_LENGTH (type), byte_order);
   /* Note that we explicitly don't worry about overflow or
      underflow.  */
   if (set)
@@ -1444,8 +1444,7 @@  stap_modify_semaphore (CORE_ADDR address, int set, struct gdbarch *gdbarch)
   else
     --value;

-  store_unsigned_integer (bytes, TYPE_LENGTH (type),
-  gdbarch_byte_order (gdbarch), value);
+  store_unsigned_integer (bytes, TYPE_LENGTH (type), byte_order, value);

   if (target_write_memory (address, bytes, TYPE_LENGTH (type)) != 0)
     warning (_("Could not write the value of a SystemTap semaphore."));
diff --git a/gdb/target-float.c b/gdb/target-float.c
index 4ef3505..caa6943 100644
--- a/gdb/target-float.c
+++ b/gdb/target-float.c
@@ -1753,7 +1753,7 @@  match_endianness (const gdb_byte *from, const struct type *type, gdb_byte *to)
 #define OPPOSITE_BYTE_ORDER BFD_ENDIAN_BIG
 #endif

-  if (gdbarch_byte_order (get_type_arch (type)) == OPPOSITE_BYTE_ORDER)
+  if (type_byte_order (type) == OPPOSITE_BYTE_ORDER)
     for (i = 0; i < len; i++)
       to[i] = from[len - i - 1];
   else
@@ -2160,8 +2160,8 @@  target_float_same_format_p (const struct type *type1,

       case TYPE_CODE_DECFLOAT:
  return (TYPE_LENGTH (type1) == TYPE_LENGTH (type2)
- && (gdbarch_byte_order (get_type_arch (type1))
-    == gdbarch_byte_order (get_type_arch (type2))));
+ && (type_byte_order (type1)
+    == type_byte_order (type2)));

       default:
  gdb_assert_not_reached ("unexpected type code");
diff --git a/gdb/testsuite/gdb.base/endianity.c b/gdb/testsuite/gdb.base/endianity.c
new file mode 100644
index 0000000..c5ee556
--- /dev/null
+++ b/gdb/testsuite/gdb.base/endianity.c
@@ -0,0 +1,44 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This tests the handling of dwarf attributes:
+    DW_AT_endianity, DW_END_big, and DW_END_little.  */
+struct otherendian
+{
+  int v;
+}
+#if defined __GNUC__ && (__GNUC__ >= 6)
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+__attribute__( ( scalar_storage_order( "big-endian" ) ) )
+#else
+__attribute__( ( scalar_storage_order( "little-endian" ) ) )
+#endif
+#endif
+;
+
+void
+do_nothing (struct otherendian *c)
+{
+}
+
+int
+main (void)
+{
+  struct otherendian o = {3};
+
+  do_nothing (&o); /* START */
+}
diff --git a/gdb/testsuite/gdb.base/endianity.exp b/gdb/testsuite/gdb.base/endianity.exp
new file mode 100644
index 0000000..7e02305
--- /dev/null
+++ b/gdb/testsuite/gdb.base/endianity.exp
@@ -0,0 +1,38 @@ 
+# Copyright 2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile .c
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+  return -1
+}
+
+set bp_location [gdb_get_line_number "START"]
+if ![runto "endianity.c:$bp_location" ] then {
+  fail "couldn't run to start"
+  return -1
+}
+
+gdb_test "print o" "= {v = 3}" "print o before assignment"
+
+gdb_test "print o.v = 4" "= 4"
+
+# scalar_storage_order requires gcc >= 6
+if { ([test_compiler_info {gcc-[0-5]-*}] || ![test_compiler_info gcc*]) } {
+  setup_xfail "*-*-*"
+}
+gdb_test "x/x &o.v" "0x04000000"
+
+gdb_test "print o" "= {v = 4}" "print o after assignment"
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 7f1b24f..835f35c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -988,7 +988,7 @@  scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
       val = allocate_value (result_type);
       store_signed_integer (value_contents_raw (val),
     TYPE_LENGTH (result_type),
-    gdbarch_byte_order (get_type_arch (result_type)),
+    type_byte_order (result_type),
     v);
     }
   else
@@ -1136,8 +1136,7 @@  scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   val = allocate_value (result_type);
   store_unsigned_integer (value_contents_raw (val),
   TYPE_LENGTH (value_type (val)),
-  gdbarch_byte_order
-    (get_type_arch (result_type)),
+  type_byte_order (result_type),
   v);
  }
       else
@@ -1266,8 +1265,7 @@  scalar_binop (struct value *arg1, struct value *arg2, enum exp_opcode op)
   val = allocate_value (result_type);
   store_signed_integer (value_contents_raw (val),
  TYPE_LENGTH (value_type (val)),
- gdbarch_byte_order
-  (get_type_arch (result_type)),
+ type_byte_order (result_type),
  v);
  }
     }
diff --git a/gdb/valops.c b/gdb/valops.c
index bfdd781..4597e99 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -483,7 +483,7 @@  value_cast (struct type *type, struct value *arg2)
       if (code2 == TYPE_CODE_PTR)
         longest = extract_unsigned_integer
     (value_contents (arg2), TYPE_LENGTH (type2),
-     gdbarch_byte_order (get_type_arch (type2)));
+     type_byte_order (type2));
       else
         longest = value_as_long (arg2);
       return value_from_longest (to_type, convert_to_boolean ?
diff --git a/gdb/valprint.c b/gdb/valprint.c
index e0eb8e1..ced0dbc 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -2402,7 +2402,7 @@  generic_emit_char (int c, struct type *type, struct ui_file *stream,
    int quoter, const char *encoding)
 {
   enum bfd_endian byte_order
-    = gdbarch_byte_order (get_type_arch (type));
+    = type_byte_order (type);
   gdb_byte *c_buf;
   int need_escape = 0;

@@ -2722,7 +2722,7 @@  generic_printstr (struct ui_file *stream, struct type *type,
   int quote_char, int c_style_terminator,
   const struct value_print_options *options)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  enum bfd_endian byte_order = type_byte_order (type);
   unsigned int i;
   int width = TYPE_LENGTH (type);
   int finished = 0;
@@ -2834,7 +2834,7 @@  val_print_string (struct type *elttype, const char *encoding,
   int bytes_read;
   gdb::unique_xmalloc_ptr<gdb_byte> buffer; /* Dynamically growable fetch buffer.  */
   struct gdbarch *gdbarch = get_type_arch (elttype);
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  enum bfd_endian byte_order = type_byte_order (elttype);
   int width = TYPE_LENGTH (elttype);

   /* First we need to figure out the limit on the number of characters we are
diff --git a/gdb/value.c b/gdb/value.c
index 47e647a..35a7a5c 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -2737,7 +2737,7 @@  value_as_address (struct value *val)
 LONGEST
 unpack_long (struct type *type, const gdb_byte *valaddr)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  enum bfd_endian byte_order = type_byte_order (type);
   enum type_code code = TYPE_CODE (type);
   int len = TYPE_LENGTH (type);
   int nosign = TYPE_UNSIGNED (type);
@@ -3100,7 +3100,7 @@  static LONGEST
 unpack_bits_as_long (struct type *field_type, const gdb_byte *valaddr,
      LONGEST bitpos, LONGEST bitsize)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (field_type));
+  enum bfd_endian byte_order = type_byte_order (field_type);
   ULONGEST val;
   ULONGEST valmask;
   int lsbcount;
@@ -3209,7 +3209,7 @@  unpack_value_bitfield (struct value *dest_val,
   int dst_bit_offset;
   struct type *field_type = value_type (dest_val);

-  byte_order = gdbarch_byte_order (get_type_arch (field_type));
+  byte_order = type_byte_order (field_type);

   /* First, unpack and sign extend the bitfield as if it was wholly
      valid.  Optimized out/unavailable bits are read as zero, but
@@ -3269,7 +3269,7 @@  void
 modify_field (struct type *type, gdb_byte *addr,
       LONGEST fieldval, LONGEST bitpos, LONGEST bitsize)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  enum bfd_endian byte_order = type_byte_order (type);
   ULONGEST oword;
   ULONGEST mask = (ULONGEST) -1 >> (8 * sizeof (ULONGEST) - bitsize);
   LONGEST bytesize;
@@ -3315,7 +3315,7 @@  modify_field (struct type *type, gdb_byte *addr,
 void
 pack_long (gdb_byte *buf, struct type *type, LONGEST num)
 {
-  enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (type));
+  enum bfd_endian byte_order = type_byte_order (type);
   LONGEST len;

   type = check_typedef (type);
@@ -3363,7 +3363,7 @@  pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)

   type = check_typedef (type);
   len = TYPE_LENGTH (type);
-  byte_order = gdbarch_byte_order (get_type_arch (type));
+  byte_order = type_byte_order (type);

   switch (TYPE_CODE (type))
     {