src/developer/debug/zxdb/symbols/dwarf_symbol_factory.cc
// We expect array types to have two things:
// - An attribute linking to the underlying type of the array.
// - One or more DW_TAG_subrange_type children that hold the size of the array in a DW_AT_count
//   attribute.
//
// The subrange child is weird because the subrange links to its own type.  LLVM generates a
// synthetic type __ARRAY_SIZE_TYPE__ that the DW_TAG_subrange_count DIE references from DW_AT_type
// attribute. We ignore this and only use the count.
//
// One might expect 2-dimensional arrays to be expressed as an array of one dimension where the
// contained type is an array of another. But both Clang and GCC generate one array entry with two
// subrange children. The order of these represents the declaration order in the code.
We expect array types to have two things:
An attribute linking to the underlying type of the array.
One or more DW_TAG_subrange_type children that hold the size of the array in a DW_AT_count
attribute.

The subrange child is weird because the subrange links to its own type.  LLVM generates a
synthetic type __ARRAY_SIZE_TYPE__ that the DW_TAG_subrange_count DIE references from DW_AT_type
attribute. We ignore this and only use the count.

One might expect 2-dimensional arrays to be expressed as an array of one dimension where the
contained type is an array of another. But both Clang and GCC generate one array entry with two
subrange children. The order of these represents the declaration order in the code.
We expect array types to have two things : An attribute linking to the underlying type of the array . One or more DW_TAG_subrange_type children that hold the size of the array in a DW_AT_count attribute . The subrange child is weird because the subrange links to its own type . LLVM generates a synthetic type __ARRAY_SIZE_TYPE__ that the DW_TAG_subrange_count DIE references from DW_AT_type attribute . We ignore this and only use the count . One might expect 2 - dimensional arrays to be expressed as an array of one dimension where the contained type is an array of another . But both Clang and GCC generate one array entry with two subrange children . The order of these represents the declaration order in the code .
fxl::RefPtr<Symbol> DwarfSymbolFactory::DecodeArrayType(const llvm::DWARFDie& die) {
  DwarfDieDecoder array_decoder(GetLLVMContext());
  llvm::DWARFDie type;
  array_decoder.AddReference(llvm::dwarf::DW_AT_type, &type);
  if (!array_decoder.Decode(die) || !type)
    return fxl::MakeRefCounted<Symbol>();
  auto contained = DecodeSymbol(type);
  if (!contained)
    return fxl::MakeRefCounted<Symbol>();
  Type* contained_type = contained->AsType();
  if (!contained_type)
    return fxl::MakeRefCounted<Symbol>();
  std::vector<std::optional<size_t>> subrange_sizes;
  for (const llvm::DWARFDie& child : die) {
    if (child.getTag() == llvm::dwarf::DW_TAG_subrange_type)
      subrange_sizes.push_back(ReadArraySubrange(GetLLVMContext(), child));
  }
  if (subrange_sizes.empty())
    return fxl::MakeRefCounted<Symbol>();
  fxl::RefPtr<Type> cur(contained_type);
  for (int i = static_cast<int>(subrange_sizes.size()) - 1; i >= 0; i--) {
    auto new_array = fxl::MakeRefCounted<ArrayType>(std::move(cur), subrange_sizes[i]);
    cur = std::move(new_array);
  }
  return cur;
}
fxl :: RefPtr < Symbol > DwarfSymbolFactory :: DecodeArrayType ( const llvm :: DWARFDie & die ) { DwarfDieDecoder array_decoder ( GetLLVMContext ( ) ) ; llvm :: DWARFDie type ; array_decoder . AddReference ( llvm :: dwarf :: DW_AT_type , & type ) ; if ( ! array_decoder . Decode ( die ) || ! type ) return fxl :: MakeRefCounted < Symbol > ( ) ; auto contained = DecodeSymbol ( type ) ; if ( ! contained ) return fxl :: MakeRefCounted < Symbol > ( ) ; Type * contained_type = contained -> AsType ( ) ; if ( ! contained_type ) return fxl :: MakeRefCounted < Symbol > ( ) ; std :: vector < std :: optional < size_t > > subrange_sizes ; for ( const llvm :: DWARFDie & child : die ) { if ( child . getTag ( ) == llvm :: dwarf :: DW_TAG_subrange_type ) subrange_sizes . push_back ( ReadArraySubrange ( GetLLVMContext ( ) , child ) ) ; } if ( subrange_sizes . empty ( ) ) return fxl :: MakeRefCounted < Symbol > ( ) ; fxl :: RefPtr < Type > cur ( contained_type ) ; for ( int i = static_cast < int > ( subrange_sizes . size ( ) ) - 1 ; i >= 0 ; i -- ) { auto new_array = fxl :: MakeRefCounted < ArrayType > ( std :: move ( cur ) , subrange_sizes [ i ] ) ; cur = std :: move ( new_array ) ; } return cur ; }
We expect array types to have two things:
 An attribute linking to the underlying type of the array.
We expect array types to have two things : An attribute linking to the underlying type of the array .
// Extract the type attribute from the root DIE (should be a DW_TAG_array_type). // Need the concrete symbol for the contained type for the array constructor. // Find all subranges stored in the declaration order. More than one means a multi-dimensional // array. // Require a subrange with a count in it. If we find cases where this isn't the case, we could add // support for array types with unknown lengths, but currently ArrayType requires a size. // Work backwards in the array dimensions generating nested array definitions. The innermost // definition refers to the contained type.