https://gcc.gnu.org/g:3e64a687a303dd550df072676c853d79076de37f

commit r15-1630-g3e64a687a303dd550df072676c853d79076de37f
Author: Mark Harmstone <m...@harmstone.com>
Date:   Tue Jun 25 17:31:24 2024 -0600

    [PATCH 09/11] Handle arrays for CodeView
    
    Translates DW_TAG_array_type DIEs into LF_ARRAY symbols.
    
    gcc/
            * dwarf2codeview.cc (struct codeview_custom_type): Add lf_array to
            union.
            (write_lf_array): New function.
            (write_custom_types): Call write_lf_array.
            (get_type_num_array_type): New function.
            (get_type_num): Handle DW_TAG_array_type DIEs.
            * dwarf2codeview.h (LF_ARRAY): Define.

Diff:
---
 gcc/dwarf2codeview.cc | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2codeview.h  |   1 +
 2 files changed, 180 insertions(+)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 9e3b64522b2..3f1ce5577fc 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -250,6 +250,12 @@ struct codeview_custom_type
       codeview_integer length;
       char *name;
     } lf_structure;
+    struct
+    {
+      uint32_t element_type;
+      uint32_t index_type;
+      codeview_integer length_in_bytes;
+    } lf_array;
   };
 };
 
@@ -1520,6 +1526,53 @@ write_lf_union (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* Write an LF_ARRAY type.  */
+
+static void
+write_lf_array (codeview_custom_type *t)
+{
+  size_t leaf_len;
+
+  /* This is lf_array in binutils and lfArray in Microsoft's cvinfo.h:
+
+    struct lf_array
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t element_type;
+      uint32_t index_type;
+      uint16_t length_in_bytes;
+      char name[];
+    } ATTRIBUTE_PACKED;
+  */
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  asm_fprintf (asm_out_file, "%LLcv_type%x_end - %LLcv_type%x_start\n",
+              t->num, t->num);
+
+  asm_fprintf (asm_out_file, "%LLcv_type%x_start:\n", t->num);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->kind);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_array.element_type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_array.index_type);
+  putc ('\n', asm_out_file);
+
+  leaf_len = 13 + write_cv_integer (&t->lf_array.length_in_bytes);
+
+  ASM_OUTPUT_ASCII (asm_out_file, "", 1);
+
+  write_cv_padding (4 - (leaf_len % 4));
+
+  asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
+}
+
 /* Write the .debug$T section, which contains all of our custom type
    definitions.  */
 
@@ -1562,6 +1615,10 @@ write_custom_types (void)
        case LF_UNION:
          write_lf_union (custom_types);
          break;
+
+       case LF_ARRAY:
+         write_lf_array (custom_types);
+         break;
        }
 
       free (custom_types);
@@ -2346,6 +2403,124 @@ get_type_num_struct (dw_die_ref type, bool in_struct, 
bool *is_fwd_ref)
   return ct->num;
 }
 
+/* Process a DW_TAG_array_type DIE, adding an LF_ARRAY type and returning its
+   number.  */
+
+static uint32_t
+get_type_num_array_type (dw_die_ref type, bool in_struct)
+{
+  dw_die_ref base_type, t, first_child, c, *dimension_arr;
+  uint64_t size = 0;
+  unsigned int dimensions, i;
+  uint32_t element_type;
+
+  base_type = get_AT_ref (type, DW_AT_type);
+  if (!base_type)
+    return 0;
+
+  /* We need to know the size of our base type.  Loop through until we find
+     it.  */
+  t = base_type;
+  while (t && size == 0)
+    {
+      switch (dw_get_die_tag (t))
+       {
+       case DW_TAG_const_type:
+       case DW_TAG_volatile_type:
+       case DW_TAG_typedef:
+       case DW_TAG_enumeration_type:
+         t = get_AT_ref (t, DW_AT_type);
+         break;
+
+       case DW_TAG_base_type:
+       case DW_TAG_structure_type:
+       case DW_TAG_class_type:
+       case DW_TAG_union_type:
+       case DW_TAG_pointer_type:
+         size = get_AT_unsigned (t, DW_AT_byte_size);
+         break;
+
+       default:
+         return 0;
+       }
+    }
+
+  if (size == 0)
+    return 0;
+
+  first_child = dw_get_die_child (type);
+  if (!first_child)
+    return 0;
+
+  element_type = get_type_num (base_type, in_struct, false);
+  if (element_type == 0)
+    return 0;
+
+  /* Create an array of our DW_TAG_subrange_type children, in reverse order.
+     We have to do this because unlike DWARF CodeView doesn't have
+     multidimensional arrays, so instead we do arrays of arrays.  */
+
+  dimensions = 0;
+  c = first_child;
+  do
+    {
+      c = dw_get_die_sib (c);
+      if (dw_get_die_tag (c) != DW_TAG_subrange_type)
+       continue;
+
+      dimensions++;
+    }
+  while (c != first_child);
+
+  if (dimensions == 0)
+    return 0;
+
+  dimension_arr = (dw_die_ref *) xmalloc (sizeof (dw_die_ref) * dimensions);
+
+  c = first_child;
+  i = 0;
+  do
+    {
+      c = dw_get_die_sib (c);
+      if (dw_get_die_tag (c) != DW_TAG_subrange_type)
+       continue;
+
+      dimension_arr[dimensions - i - 1] = c;
+      i++;
+    }
+  while (c != first_child);
+
+  /* Record an LF_ARRAY entry for each array dimension.  If this leads to
+     duplicate types, ld will take care of it for us.  */
+
+  for (i = 0; i < dimensions; i++)
+    {
+      codeview_custom_type *ct;
+      dw_die_ref index;
+
+      ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+      size *= get_AT_unsigned (dimension_arr[i], DW_AT_upper_bound) + 1;
+
+      index = get_AT_ref (dimension_arr[i], DW_AT_type);
+
+      ct->next = NULL;
+      ct->kind = LF_ARRAY;
+      ct->lf_array.element_type = element_type;
+      ct->lf_array.index_type = get_type_num (index, in_struct, false);
+      ct->lf_array.length_in_bytes.neg = false;
+      ct->lf_array.length_in_bytes.num = size;
+
+      add_custom_type (ct);
+
+      element_type = ct->num;
+    }
+
+  free (dimension_arr);
+
+  return element_type;
+}
+
 /* Process a DIE representing a type definition, add a CodeView type if
    necessary, and return its number.  If it's something we can't handle, return
    0.  We keep a hash table so that we're not adding the same type multiple
@@ -2407,6 +2582,10 @@ get_type_num (dw_die_ref type, bool in_struct, bool 
no_fwd_ref)
       num = get_type_num_struct (type, in_struct, &is_fwd_ref);
       break;
 
+    case DW_TAG_array_type:
+      num = get_type_num_array_type (type, in_struct);
+      break;
+
     default:
       num = 0;
       break;
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index e60fe86e673..70eed6bf2aa 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.  If not see
 #define LF_FIELDLIST           0x1203
 #define LF_INDEX               0x1404
 #define LF_ENUMERATE           0x1502
+#define LF_ARRAY               0x1503
 #define LF_CLASS               0x1504
 #define LF_STRUCTURE           0x1505
 #define LF_UNION               0x1506

Reply via email to