gollvm: enhance llvm-godumpspec handling of bitfields

Rework the code that detects bitfields in structures, which was
insufficiently flexible relative to recent changes in the DWARF
emitted by clang/gcc. In particular:

 - handle both the legacy DW_AT_bit_offset and the more recent
   DW_AT_data_bit_offset

 - fall back on the underlying type ref to determine the byte size for
   a field if DW_AT_byte_size is not present (the most recent version
   of GCC has started to leave it out).

Change-Id: Ibad3f3d575c06babcdb760e2e5f5623e8b45e59b
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/290672
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Trust: Than McIntosh <thanm@google.com>
diff --git a/libgo/godumpspec/godumpspec.cpp b/libgo/godumpspec/godumpspec.cpp
index c802ac1..4abf442 100644
--- a/libgo/godumpspec/godumpspec.cpp
+++ b/libgo/godumpspec/godumpspec.cpp
@@ -772,20 +772,39 @@
   return rval;
 }
 
+// isBitField returns TRUE if a given member or field is a bitfield.
+//
+// Notes:
+// - some compilers emit DW_AT_bit_offset for bitfields and others use the
+//   more recent DW_AT_data_bit_offset; we need to handle both.
+// - older versions of GCC emit DW_AT_byte_size for all fields; newer
+//   versions leave this out (presumably assuming that the size can be
+//   derived from the underlying type). Use the byte size attribute if
+//   present, otherwise fall back on the type ref.
 bool GoDumpHelper::isBitField(const DWARFDie &die)
 {
   auto bitSize = die.find(dwarf::DW_AT_bit_size);
   if (!bitSize)
     return false;
+  uint64_t tsz = 0;
   auto byteSize = die.find(dwarf::DW_AT_byte_size);
-  auto bitOffset = die.find(dwarf::DW_AT_bit_offset);
-  assert(bitSize && bitOffset);
-  auto byval = byteSize->getAsUnsignedConstant();
+  if (!byteSize) {
+    tsz = typeOfSize(die);
+  } else {
+    auto byval = byteSize->getAsUnsignedConstant();
+    assert(byval);
+    tsz = *byval;
+  }
+  auto bitOffset = die.find(dwarf::DW_AT_data_bit_offset);
+  if (!bitOffset) {
+    bitOffset = die.find(dwarf::DW_AT_bit_offset);
+  }
+  assert(bitOffset);
   auto bsval = bitSize->getAsUnsignedConstant();
   auto boval = bitOffset->getAsUnsignedConstant();
-  assert(byval && bsval && boval);
+  assert(bsval && boval);
   if (*boval % *bsval == 0 &&
-      *bsval % *byval == 0 &&
+      *bsval % tsz == 0 &&
       (*bsval == 8 || *bsval == 16 || *bsval == 32 || *bsval == 64))
     return false;
   return true;