public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 00/11] CodeView variables and type system
@ 2024-06-18  0:17 Mark Harmstone
  2024-06-18  0:17 ` [PATCH 01/11] Output CodeView data about variables Mark Harmstone
                   ` (10 more replies)
  0 siblings, 11 replies; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

This patch series adds support for outputting global variables when the
-gcodeview option is provided, along with the type system to go along
with this.

As with previous patches, the best way to see the output is run
Microsoft's cvdump.exe against the object file:
https://github.com/microsoft/microsoft-pdb/raw/master/cvdump/cvdump.exe

You'll also need a recentish version of binutils in order to get ld to
output an actual PDB file that can be read by MSVC or windbg.

This ought to be fairly complete as far as C is concerned. Still to come
are functions, local variables, and some C++ things.

Mark Harmstone (11):
  Output CodeView data about variables
  Handle CodeView base types
  Handle typedefs for CodeView
  Handle pointers for CodeView
  Handle const and varible modifiers for CodeView
  Handle enums for CodeView
  Handle structs and classes for CodeView
  Handle unions for CodeView.
  Handle arrays for CodeView
  Handle bitfields for CodeView
  Handle subroutine types in CodeView

 gcc/dwarf2codeview.cc | 2278 ++++++++++++++++++++++++++++++++++++++++-
 gcc/dwarf2codeview.h  |   67 ++
 gcc/dwarf2out.cc      |    5 +
 3 files changed, 2341 insertions(+), 9 deletions(-)

-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/11] Output CodeView data about variables
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-23 23:50   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 02/11] Handle CodeView base types Mark Harmstone
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Parse the DW_TAG_variable DIEs, and outputs S_GDATA32 (for global variables)
and S_LDATA32 (static global variables) symbols into the .debug$S section.

    gcc/
            * dwarf2codeview.cc (S_LDATA32, S_GDATA32): Define.
            (struct codeview_symbol): New structure.
            (sym, last_sym): New variables.
            (write_data_symbol): New function.
            (write_codeview_symbols): Call write_data_symbol.
            (add_variable, codeview_debug_early_finish): New functions.
            * dwarf2codeview.h (codeview_debug_early_finish): Prototype.
            * dwarf2out.cc
            (dwarf2out_early_finish): Call codeview_debug_early_finish.
---
 gcc/dwarf2codeview.cc | 160 ++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2codeview.h  |   1 +
 gcc/dwarf2out.cc      |   5 ++
 3 files changed, 166 insertions(+)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index db776d79be4..60e84635971 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -46,6 +46,8 @@ along with GCC; see the file COPYING3.  If not see
 
 #define CHKSUM_TYPE_MD5		1
 
+#define S_LDATA32		0x110c
+#define S_GDATA32		0x110d
 #define S_COMPILE3		0x113c
 
 #define CV_CFL_80386		0x03
@@ -129,6 +131,22 @@ struct codeview_function
   codeview_line_block *blocks, *last_block;
 };
 
+struct codeview_symbol
+{
+  codeview_symbol *next;
+  uint16_t kind;
+
+  union
+  {
+    struct
+    {
+      uint32_t type;
+      char *name;
+      dw_die_ref die;
+    } data_symbol;
+  };
+};
+
 static unsigned int line_label_num;
 static unsigned int func_label_num;
 static unsigned int sym_label_num;
@@ -140,6 +158,7 @@ static codeview_string *strings, *last_string;
 static codeview_function *funcs, *last_func;
 static const char* last_filename;
 static uint32_t last_file_id;
+static codeview_symbol *sym, *last_sym;
 
 /* Record new line number against the current function.  */
 
@@ -698,6 +717,77 @@ write_compile3_symbol (void)
   targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
 }
 
+/* Write an S_GDATA32 symbol, representing a global variable, or an S_LDATA32
+   symbol, for a static global variable.  */
+
+static void
+write_data_symbol (codeview_symbol *s)
+{
+  unsigned int label_num = ++sym_label_num;
+  dw_attr_node *loc;
+  dw_loc_descr_ref loc_ref;
+
+  /* This is struct datasym in binutils:
+
+      struct datasym
+      {
+	uint16_t size;
+	uint16_t kind;
+	uint32_t type;
+	uint32_t offset;
+	uint16_t section;
+	char name[];
+      } ATTRIBUTE_PACKED;
+  */
+
+  /* Extract the DW_AT_location attribute from the DIE, and make sure it's in
+     in a format we can parse.  */
+
+  loc = get_AT (s->data_symbol.die, DW_AT_location);
+  if (!loc)
+    goto end;
+
+  if (loc->dw_attr_val.val_class != dw_val_class_loc)
+    goto end;
+
+  loc_ref = loc->dw_attr_val.v.val_loc;
+  if (!loc_ref || loc_ref->dw_loc_opc != DW_OP_addr)
+    goto end;
+
+  /* Output the S_GDATA32 / S_LDATA32 record.  */
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  asm_fprintf (asm_out_file,
+	       "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n",
+	       label_num, label_num);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, s->kind);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, s->data_symbol.type);
+  putc ('\n', asm_out_file);
+
+  asm_fprintf (asm_out_file, "\t.secrel32 ");
+  output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr);
+  fputc ('\n', asm_out_file);
+
+  asm_fprintf (asm_out_file, "\t.secidx ");
+  output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr);
+  fputc ('\n', asm_out_file);
+
+  ASM_OUTPUT_ASCII (asm_out_file, s->data_symbol.name,
+		    strlen (s->data_symbol.name) + 1);
+
+  targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num);
+
+end:
+  free (s->data_symbol.name);
+}
+
 /* Write the CodeView symbols into the .debug$S section.  */
 
 static void
@@ -714,6 +804,22 @@ write_codeview_symbols (void)
 
   write_compile3_symbol ();
 
+  while (sym)
+    {
+      codeview_symbol *n = sym->next;
+
+      switch (sym->kind)
+	{
+	case S_LDATA32:
+	case S_GDATA32:
+	  write_data_symbol (sym);
+	  break;
+	}
+
+      free (sym);
+      sym = n;
+    }
+
   asm_fprintf (asm_out_file, "%LLcv_syms_end:\n");
 }
 
@@ -734,4 +840,58 @@ codeview_debug_finish (void)
   write_codeview_symbols ();
 }
 
+/* Process a DW_TAG_variable DIE, and add an S_GDATA32 or S_LDATA32 symbol for
+   this.  */
+
+static void
+add_variable (dw_die_ref die)
+{
+  codeview_symbol *s;
+  const char *name;
+
+  name = get_AT_string (die, DW_AT_name);
+  if (!name)
+    return;
+
+  s = (codeview_symbol *) xmalloc (sizeof (codeview_symbol));
+
+  s->next = NULL;
+  s->kind = get_AT (die, DW_AT_external) ? S_GDATA32 : S_LDATA32;
+  s->data_symbol.type = 0;
+  s->data_symbol.name = xstrdup (name);
+  s->data_symbol.die = die;
+
+  if (last_sym)
+    last_sym->next = s;
+  else
+    sym = s;
+
+  last_sym = s;
+}
+
+/* Loop through the DIEs that have been output for our TU, and add CodeView
+   symbols for them.  */
+
+void
+codeview_debug_early_finish (dw_die_ref die)
+{
+  dw_die_ref first_child, c;
+
+  first_child = dw_get_die_child (die);
+
+  if (!first_child)
+    return;
+
+  c = first_child;
+
+  do
+    {
+      if (dw_get_die_tag (c) == DW_TAG_variable)
+	add_variable (c);
+
+      c = dw_get_die_sib (c);
+    }
+  while (c != first_child);
+}
+
 #endif
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index b6421b62d2e..ac4c2fd21c2 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -30,5 +30,6 @@ extern void codeview_source_line (unsigned int, const char *);
 extern void codeview_start_source_file (const char *);
 extern void codeview_switch_text_section ();
 extern void codeview_end_epilogue (void);
+extern void codeview_debug_early_finish (dw_die_ref die);
 
 #endif /* GCC_DWARF2CODEVIEW_H */
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index 5b064ffd78a..f6939b60077 100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -33208,6 +33208,11 @@ dwarf2out_early_finish (const char *filename)
       ctf_debug_early_finish (filename);
     }
 
+#ifdef CODEVIEW_DEBUGGING_INFO
+  if (codeview_debuginfo_p ())
+    codeview_debug_early_finish (comp_unit_die ());
+#endif
+
   /* Do not generate DWARF assembler now when not producing LTO bytecode.  */
   if ((!flag_generate_lto && !flag_generate_offload)
       /* FIXME: Disable debug info generation for (PE-)COFF targets since the
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 02/11] Handle CodeView base types
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
  2024-06-18  0:17 ` [PATCH 01/11] Output CodeView data about variables Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-24  0:18   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 03/11] Handle typedefs for CodeView Mark Harmstone
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Adds a get_type_num function to translate type DIEs into CodeView
numbers, along with a hash table for this.  For now we just deal with
the base types (integers, Unicode chars, floats, and bools).

    gcc/
            * dwarf2codeview.cc (struct codeview_type): New structure.
            (struct die_hasher): Likewise.
            (types_htab): New variable.
            (codeview_debug_finish): Free types_htab if allocated.
            (get_type_num_base_type, get_type_num): New function.
            (add_variable): Call get_type_num.
            * dwarf2codeview.h (T_CHAR, T_SHORT, T_LONG, T_QUAD): Define.
            (T_UCHAR, T_USHORT, T_ULONG, T_UQUAD, T_BOOL08): Likewise.
            (T_REAL32, T_REAL64, T_REAL80, T_REAL128, T_RCHAR): Likewise.
            (T_WCHAR, T_INT4, T_UINT4, T_CHAR16, T_CHAR32, T_CHAR8): Likewise.
---
 gcc/dwarf2codeview.cc | 196 +++++++++++++++++++++++++++++++++++++++++-
 gcc/dwarf2codeview.h  |  23 +++++
 2 files changed, 218 insertions(+), 1 deletion(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 60e84635971..eb7c1270e31 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -147,6 +147,27 @@ struct codeview_symbol
   };
 };
 
+struct codeview_type
+{
+  dw_die_ref die;
+  uint32_t num;
+};
+
+struct die_hasher : free_ptr_hash <codeview_type>
+{
+  typedef dw_die_ref compare_type;
+
+  static hashval_t hash (const codeview_type *x)
+  {
+    return htab_hash_pointer (x->die);
+  }
+
+  static bool equal (const codeview_type *x, const dw_die_ref y)
+  {
+    return x->die == y;
+  }
+};
+
 static unsigned int line_label_num;
 static unsigned int func_label_num;
 static unsigned int sym_label_num;
@@ -159,6 +180,7 @@ static codeview_function *funcs, *last_func;
 static const char* last_filename;
 static uint32_t last_file_id;
 static codeview_symbol *sym, *last_sym;
+static hash_table<die_hasher> *types_htab;
 
 /* Record new line number against the current function.  */
 
@@ -838,6 +860,178 @@ codeview_debug_finish (void)
   write_source_files ();
   write_line_numbers ();
   write_codeview_symbols ();
+
+  if (types_htab)
+    delete types_htab;
+}
+
+/* Translate a DWARF base type (DW_TAG_base_type) into its CodeView
+   equivalent.  */
+
+static uint32_t
+get_type_num_base_type (dw_die_ref type)
+{
+  unsigned int size = get_AT_unsigned (type, DW_AT_byte_size);
+
+  switch (get_AT_unsigned (type, DW_AT_encoding))
+    {
+    case DW_ATE_signed_char:
+      {
+	const char *name = get_AT_string (type, DW_AT_name);
+
+	if (size != 1)
+	  return 0;
+
+	if (name && !strcmp (name, "signed char"))
+	  return T_CHAR;
+	else
+	  return T_RCHAR;
+      }
+
+    case DW_ATE_unsigned_char:
+      if (size != 1)
+	return 0;
+
+      return T_UCHAR;
+
+    case DW_ATE_signed:
+      switch (size)
+	{
+	case 2:
+	  return T_SHORT;
+
+	case 4:
+	  {
+	    const char *name = get_AT_string (type, DW_AT_name);
+
+	    if (name && !strcmp (name, "int"))
+	      return T_INT4;
+	    else
+	      return T_LONG;
+	  }
+
+	case 8:
+	  return T_QUAD;
+
+	default:
+	  return 0;
+	}
+
+    case DW_ATE_unsigned:
+      switch (size)
+	{
+	case 2:
+	  {
+	    const char *name = get_AT_string (type, DW_AT_name);
+
+	    if (name && !strcmp (name, "wchar_t"))
+	      return T_WCHAR;
+	    else
+	      return T_USHORT;
+	  }
+
+	case 4:
+	  {
+	    const char *name = get_AT_string (type, DW_AT_name);
+
+	    if (name && !strcmp (name, "unsigned int"))
+	      return T_UINT4;
+	    else
+	      return T_ULONG;
+	  }
+
+	case 8:
+	  return T_UQUAD;
+
+	default:
+	  return 0;
+	}
+
+    case DW_ATE_UTF:
+      switch (size)
+	{
+	case 1:
+	  return T_CHAR8;
+
+	case 2:
+	  return T_CHAR16;
+
+	case 4:
+	  return T_CHAR32;
+
+	default:
+	  return 0;
+	}
+
+    case DW_ATE_float:
+      switch (size)
+	{
+	case 4:
+	  return T_REAL32;
+
+	case 8:
+	  return T_REAL64;
+
+	case 12:
+	  return T_REAL80;
+
+	case 16:
+	  return T_REAL128;
+
+	default:
+	  return 0;
+	}
+
+    case DW_ATE_boolean:
+      if (size == 1)
+	return T_BOOL08;
+      else
+	return 0;
+
+    default:
+      return 0;
+    }
+}
+
+/* Process a DIE representing a type definition 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 times - though if we do it's not
+   disastrous, as ld will deduplicate everything for us.  */
+
+static uint32_t
+get_type_num (dw_die_ref type)
+{
+  codeview_type **slot, *t;
+
+  if (!type)
+    return 0;
+
+  if (!types_htab)
+    types_htab = new hash_table<die_hasher> (10);
+
+  slot = types_htab->find_slot_with_hash (type, htab_hash_pointer (type),
+					  INSERT);
+
+  if (*slot)
+    return (*slot)->num;
+
+  t = (codeview_type *) xmalloc (sizeof (codeview_type));
+  t->die = type;
+
+  switch (dw_get_die_tag (type))
+    {
+    case DW_TAG_base_type:
+      t->num = get_type_num_base_type (type);
+      break;
+
+    default:
+      t->num = 0;
+      break;
+    }
+
+  *slot = t;
+
+  return t->num;
 }
 
 /* Process a DW_TAG_variable DIE, and add an S_GDATA32 or S_LDATA32 symbol for
@@ -857,7 +1051,7 @@ add_variable (dw_die_ref die)
 
   s->next = NULL;
   s->kind = get_AT (die, DW_AT_external) ? S_GDATA32 : S_LDATA32;
-  s->data_symbol.type = 0;
+  s->data_symbol.type = get_type_num (get_AT_ref (die, DW_AT_type));
   s->data_symbol.name = xstrdup (name);
   s->data_symbol.die = die;
 
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index ac4c2fd21c2..7d8a4c161f4 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -23,6 +23,29 @@ along with GCC; see the file COPYING3.  If not see
 #include "dwarf2out.h"
 #include "flags.h"
 
+/* Constants for in-built types.  */
+
+#define T_CHAR			0x0010
+#define T_SHORT			0x0011
+#define T_LONG			0x0012
+#define T_QUAD			0x0013
+#define T_UCHAR			0x0020
+#define T_USHORT		0x0021
+#define T_ULONG			0x0022
+#define T_UQUAD			0x0023
+#define T_BOOL08		0x0030
+#define T_REAL32		0x0040
+#define T_REAL64		0x0041
+#define T_REAL80		0x0042
+#define T_REAL128		0x0043
+#define T_RCHAR			0x0070
+#define T_WCHAR			0x0071
+#define T_INT4			0x0074
+#define T_UINT4			0x0075
+#define T_CHAR16		0x007a
+#define T_CHAR32		0x007b
+#define T_CHAR8			0x007c
+
 /* Debug Format Interface.  Used in dwarf2out.cc.  */
 
 extern void codeview_debug_finish (void);
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 03/11] Handle typedefs for CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
  2024-06-18  0:17 ` [PATCH 01/11] Output CodeView data about variables Mark Harmstone
  2024-06-18  0:17 ` [PATCH 02/11] Handle CodeView base types Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-24  0:30   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 04/11] Handle pointers " Mark Harmstone
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

    gcc/
            * dwarf2codeview.cc (get_type_num): Handle typedefs.
---
 gcc/dwarf2codeview.cc | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index eb7c1270e31..5006a176260 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -1024,6 +1024,12 @@ get_type_num (dw_die_ref type)
       t->num = get_type_num_base_type (type);
       break;
 
+    case DW_TAG_typedef:
+      /* FIXME - signed longs typedef'd as "HRESULT" should get their
+		 own type (T_HRESULT) */
+      t->num = get_type_num (get_AT_ref (type, DW_AT_type));
+      break;
+
     default:
       t->num = 0;
       break;
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 04/11] Handle pointers for CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (2 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 03/11] Handle typedefs for CodeView Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-24  3:31   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 05/11] Handle const and varible modifiers " Mark Harmstone
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Translates DW_TAG_pointer_type DIEs into LF_POINTER symbols, which get
output into the .debug$T section.

    gcc/
            * dwarf2codeview.cc (FIRST_TYPE): Define.
            (struct codeview_custom_type): New structure.
            (custom_types, last_custom_type): New variables.
            (get_type_num): Prototype.
            (write_lf_pointer, write_custom_types): New functions.
            (codeview_debug_finish): Call write_custom_types.
            (add_custom_type, get_type_num_pointer_type): New functions.
            (get_type_num): Handle DW_TAG_pointer_type DIEs.
            * dwarf2codeview.h (T_VOID): Define.
            (CV_POINTER_32, CV_POINTER_64): Likewise.
            (T_32PVOID, T_64PVOID): Likewise.
            (CV_PTR_NEAR32, CV_PTR64, LF_POINTER): Likewise.
---
 gcc/dwarf2codeview.cc | 179 +++++++++++++++++++++++++++++++++++++++++-
 gcc/dwarf2codeview.h  |  13 +++
 2 files changed, 188 insertions(+), 4 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 5006a176260..51401f2d5bc 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -56,6 +56,8 @@ along with GCC; see the file COPYING3.  If not see
 #define CV_CFL_C		0x00
 #define CV_CFL_CXX		0x01
 
+#define FIRST_TYPE		0x1000
+
 #define LINE_LABEL	"Lcvline"
 #define END_FUNC_LABEL	"Lcvendfunc"
 #define SYMBOL_START_LABEL	"Lcvsymstart"
@@ -168,6 +170,22 @@ struct die_hasher : free_ptr_hash <codeview_type>
   }
 };
 
+struct codeview_custom_type
+{
+  struct codeview_custom_type *next;
+  uint32_t num;
+  uint16_t kind;
+
+  union
+  {
+    struct
+    {
+      uint32_t base_type;
+      uint32_t attributes;
+    } lf_pointer;
+  };
+};
+
 static unsigned int line_label_num;
 static unsigned int func_label_num;
 static unsigned int sym_label_num;
@@ -181,6 +199,9 @@ static const char* last_filename;
 static uint32_t last_file_id;
 static codeview_symbol *sym, *last_sym;
 static hash_table<die_hasher> *types_htab;
+static codeview_custom_type *custom_types, *last_custom_type;
+
+static uint32_t get_type_num (dw_die_ref type);
 
 /* Record new line number against the current function.  */
 
@@ -845,6 +866,71 @@ write_codeview_symbols (void)
   asm_fprintf (asm_out_file, "%LLcv_syms_end:\n");
 }
 
+/* Write an LF_POINTER type.  */
+
+static void
+write_lf_pointer (codeview_custom_type *t)
+{
+  /* This is lf_pointer in binutils and lfPointer in Microsoft's cvinfo.h:
+
+    struct lf_pointer
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t base_type;
+      uint32_t attributes;
+    } 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_pointer.base_type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_pointer.attributes);
+  putc ('\n', asm_out_file);
+
+  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.  */
+
+static void
+write_custom_types (void)
+{
+  targetm.asm_out.named_section (".debug$T", SECTION_DEBUG, NULL);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, CV_SIGNATURE_C13);
+  putc ('\n', asm_out_file);
+
+  while (custom_types)
+    {
+      codeview_custom_type *n = custom_types->next;
+
+      switch (custom_types->kind)
+	{
+	case LF_POINTER:
+	  write_lf_pointer (custom_types);
+	  break;
+	}
+
+      free (custom_types);
+      custom_types = n;
+    }
+}
+
 /* Finish CodeView debug info emission.  */
 
 void
@@ -861,6 +947,9 @@ codeview_debug_finish (void)
   write_line_numbers ();
   write_codeview_symbols ();
 
+  if (custom_types)
+    write_custom_types ();
+
   if (types_htab)
     delete types_htab;
 }
@@ -993,10 +1082,88 @@ get_type_num_base_type (dw_die_ref type)
     }
 }
 
-/* Process a DIE representing a type definition 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 times - though if we do it's not
-   disastrous, as ld will deduplicate everything for us.  */
+/* Add a new codeview_custom_type to our singly-linked custom_types list.  */
+
+static void
+add_custom_type (codeview_custom_type *ct)
+{
+  uint32_t num;
+
+  if (last_custom_type)
+    {
+      num = last_custom_type->num + 1;
+      last_custom_type->next = ct;
+    }
+  else
+    {
+      num = FIRST_TYPE;
+      custom_types = ct;
+    }
+
+  last_custom_type = ct;
+
+  ct->num = num;
+}
+
+/* Process a DW_TAG_pointer_type DIE.  If this is a pointer to a builtin
+   type, return the predefined constant for this.  Otherwise, add a new
+   LF_POINTER type and return its number.  */
+
+static uint32_t
+get_type_num_pointer_type (dw_die_ref type)
+{
+  uint32_t base_type_num, byte_size;
+  dw_die_ref base_type;
+  codeview_custom_type *ct;
+
+  byte_size = get_AT_unsigned (type, DW_AT_byte_size);
+  if (byte_size != 4 && byte_size != 8)
+    return 0;
+
+  base_type = get_AT_ref (type, DW_AT_type);
+
+  /* If DW_AT_type is not set, this must be a void pointer.  */
+  if (!base_type)
+    return byte_size == 4 ? T_32PVOID : T_64PVOID;
+
+  base_type_num = get_type_num (base_type);
+  if (base_type_num == 0)
+    return 0;
+
+  /* Pointers to builtin types have predefined type numbers, with the top byte
+     determining the pointer size - 0x0400 for a 32-bit pointer and 0x0600
+     for 64-bit.  */
+  if (base_type_num < FIRST_TYPE && !(base_type_num & 0xff00))
+    {
+      if (byte_size == 4)
+	return CV_POINTER_32 | base_type_num;
+      else
+	return CV_POINTER_64 | base_type_num;
+    }
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_POINTER;
+  ct->lf_pointer.base_type = base_type_num;
+
+  if (byte_size == 4)
+    ct->lf_pointer.attributes = CV_PTR_NEAR32;
+  else
+    ct->lf_pointer.attributes = CV_PTR_64;
+
+  ct->lf_pointer.attributes |= byte_size << 13;
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
+/* 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
+   times - though if we do it's not disastrous, as ld will deduplicate
+   everything for us.  */
 
 static uint32_t
 get_type_num (dw_die_ref type)
@@ -1030,6 +1197,10 @@ get_type_num (dw_die_ref type)
       t->num = get_type_num (get_AT_ref (type, DW_AT_type));
       break;
 
+    case DW_TAG_pointer_type:
+      t->num = get_type_num_pointer_type (type);
+      break;
+
     default:
       t->num = 0;
       break;
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index 7d8a4c161f4..0af4c98250f 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 
 /* Constants for in-built types.  */
 
+#define T_VOID			0x0003
 #define T_CHAR			0x0010
 #define T_SHORT			0x0011
 #define T_LONG			0x0012
@@ -46,6 +47,18 @@ along with GCC; see the file COPYING3.  If not see
 #define T_CHAR32		0x007b
 #define T_CHAR8			0x007c
 
+#define CV_POINTER_32		0x0400
+#define CV_POINTER_64		0x0600
+#define T_32PVOID		(T_VOID | CV_POINTER_32)
+#define T_64PVOID		(T_VOID | CV_POINTER_64)
+
+/* LF_POINTER attributes.  */
+#define CV_PTR_NEAR32		0x0a
+#define CV_PTR_64		0x0c
+
+/* Constants for type definitions.  */
+#define LF_POINTER		0x1002
+
 /* Debug Format Interface.  Used in dwarf2out.cc.  */
 
 extern void codeview_debug_finish (void);
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 05/11] Handle const and varible modifiers for CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (3 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 04/11] Handle pointers " Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-24  3:39   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 06/11] Handle enums " Mark Harmstone
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Translate DW_TAG_const_type and DW_TAG_volatile_type DIEs into
LF_MODIFIER symbols.

    gcc/
            * dwarf2codeview.cc
            (struct codeview_custom_type): Add lf_modifier to union.
            (write_cv_padding, write_lf_modifier): New functions.
            (write_custom_types): Call write_lf_modifier.
            (get_type_num_const_type): New function.
            (get_type_num_volatile_type): Likewise.
            (get_type_num): Handle DW_TAG_const_type and
                DW_TAG_volatile_type DIEs.
            * dwarf2codeview.h (MOD_const, MOD_volatile): Define.
            (LF_MODIFIER): Likewise.
---
 gcc/dwarf2codeview.cc | 157 ++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2codeview.h  |   5 ++
 2 files changed, 162 insertions(+)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 51401f2d5bc..05f5f60997e 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -183,6 +183,11 @@ struct codeview_custom_type
       uint32_t base_type;
       uint32_t attributes;
     } lf_pointer;
+    struct
+    {
+      uint32_t base_type;
+      uint16_t modifier;
+    } lf_modifier;
   };
 };
 
@@ -903,6 +908,76 @@ write_lf_pointer (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* All CodeView type definitions have to be aligned to a four-byte boundary,
+   so write some padding bytes if necessary.  These have to be specific values:
+   f3, f2, f1.  */
+
+static void
+write_cv_padding (size_t padding)
+{
+  if (padding == 4 || padding == 0)
+    return;
+
+  if (padding == 3)
+    {
+      fputs (integer_asm_op (1, false), asm_out_file);
+      fprint_whex (asm_out_file, 0xf3);
+      putc ('\n', asm_out_file);
+    }
+
+  if (padding >= 2)
+    {
+      fputs (integer_asm_op (1, false), asm_out_file);
+      fprint_whex (asm_out_file, 0xf2);
+      putc ('\n', asm_out_file);
+    }
+
+  fputs (integer_asm_op (1, false), asm_out_file);
+  fprint_whex (asm_out_file, 0xf1);
+  putc ('\n', asm_out_file);
+}
+
+/* Write an LF_MODIFIER type, representing a const and/or volatile modification
+   of another type.  */
+
+static void
+write_lf_modifier (codeview_custom_type *t)
+{
+  /* This is lf_modifier in binutils and lfModifier in Microsoft's cvinfo.h:
+
+    struct lf_modifier
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t base_type;
+      uint16_t modifier;
+      uint16_t padding;
+    } 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_modifier.base_type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_modifier.modifier);
+  putc ('\n', asm_out_file);
+
+  write_cv_padding (2);
+
+  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.  */
 
@@ -924,6 +999,10 @@ write_custom_types (void)
 	case LF_POINTER:
 	  write_lf_pointer (custom_types);
 	  break;
+
+	case LF_MODIFIER:
+	  write_lf_modifier (custom_types);
+	  break;
 	}
 
       free (custom_types);
@@ -1159,6 +1238,76 @@ get_type_num_pointer_type (dw_die_ref type)
   return ct->num;
 }
 
+/* Process a DW_TAG_const_type DIE, adding an LF_MODIFIER type and returning
+   its number.  */
+
+static uint32_t
+get_type_num_const_type (dw_die_ref type)
+{
+  dw_die_ref base_type;
+  uint32_t base_type_num;
+  codeview_custom_type *ct;
+  bool is_volatile = false;
+
+  base_type = get_AT_ref (type, DW_AT_type);
+  if (!base_type)
+    return 0;
+
+  /* Handle case when this is a const volatile type - we only need one
+     LF_MODIFIER for this.  */
+  if (dw_get_die_tag (base_type) == DW_TAG_volatile_type)
+    {
+      is_volatile = true;
+
+      base_type = get_AT_ref (base_type, DW_AT_type);
+      if (!base_type)
+	return 0;
+    }
+
+  base_type_num = get_type_num (base_type);
+  if (base_type_num == 0)
+    return 0;
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_MODIFIER;
+  ct->lf_modifier.base_type = base_type_num;
+  ct->lf_modifier.modifier = MOD_const;
+
+  if (is_volatile)
+    ct->lf_modifier.modifier |= MOD_volatile;
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
+/* Process a DW_TAG_volatile_type DIE, adding an LF_MODIFIER type and
+   returning its number.  */
+
+static uint32_t
+get_type_num_volatile_type (dw_die_ref type)
+{
+  uint32_t base_type_num;
+  codeview_custom_type *ct;
+
+  base_type_num = get_type_num (get_AT_ref (type, DW_AT_type));
+  if (base_type_num == 0)
+    return 0;
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_MODIFIER;
+  ct->lf_modifier.base_type = base_type_num;
+  ct->lf_modifier.modifier = MOD_volatile;
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
 /* 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
@@ -1201,6 +1350,14 @@ get_type_num (dw_die_ref type)
       t->num = get_type_num_pointer_type (type);
       break;
 
+    case DW_TAG_const_type:
+      t->num = get_type_num_const_type (type);
+      break;
+
+    case DW_TAG_volatile_type:
+      t->num = get_type_num_volatile_type (type);
+      break;
+
     default:
       t->num = 0;
       break;
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index 0af4c98250f..d48cfbebc32 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -56,7 +56,12 @@ along with GCC; see the file COPYING3.  If not see
 #define CV_PTR_NEAR32		0x0a
 #define CV_PTR_64		0x0c
 
+/* LF_MODIFIER values.  */
+#define MOD_const		0x1
+#define MOD_volatile		0x2
+
 /* Constants for type definitions.  */
+#define LF_MODIFIER		0x1001
 #define LF_POINTER		0x1002
 
 /* Debug Format Interface.  Used in dwarf2out.cc.  */
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 06/11] Handle enums for CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (4 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 05/11] Handle const and varible modifiers " Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-24  3:49   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 07/11] Handle structs and classes " Mark Harmstone
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Translates DW_TAG_enumeration_type DIEs into LF_ENUM symbols.

    gcc/
            * dwarf2codeview.cc (MAX_FIELDLIST_SIZE): Define.
            (struct codeview_integer): New structure.
            (struct codeview_subtype): Likewise
            (struct codeview_custom_type): Add lf_fieldlist and lf_enum
                to union.
            (write_cv_integer, cv_integer_len): New functions.
            (write_lf_fieldlist, write_lf_enum): Likewise.
            (write_custom_types): Call write_lf_fieldlist and write_lf_enum.
            (add_enum_forward_def): New function.
            (get_type_num_enumeration_type): Likewise.
            (get_type_num): Handle DW_TAG_enumeration_type DIEs.
            * dwarf2codeview.h (LF_FIELDLIST, LF_INDEX, LF_ENUMERATE): Define.
            (LF_ENUM, LF_CHAR, LF_SHORT, LF_USHORT, LF_LONG): Likewise.
            (LF_ULONG, LF_QUADWORD, LF_UQUADWORD): Likewise.
            (CV_ACCESS_PRIVATE, CV_ACCESS_PROTECTED): Likewise.
            (CV_ACCESS_PUBLIC, CV_PROP_FWDREF): Likewise.
---
 gcc/dwarf2codeview.cc | 524 ++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2codeview.h  |  17 ++
 2 files changed, 541 insertions(+)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 05f5f60997e..475a53573e9 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -63,6 +63,11 @@ along with GCC; see the file COPYING3.  If not see
 #define SYMBOL_START_LABEL	"Lcvsymstart"
 #define SYMBOL_END_LABEL	"Lcvsymend"
 
+/* There's two bytes available for each type's size, but follow MSVC's lead in
+   capping the LF_FIELDLIST size at fb00 (minus 8 bytes for the LF_INDEX
+   pointing to the overflow entry).  */
+#define MAX_FIELDLIST_SIZE	0xfaf8
+
 #define HASH_SIZE 16
 
 struct codeview_string
@@ -170,6 +175,31 @@ struct die_hasher : free_ptr_hash <codeview_type>
   }
 };
 
+struct codeview_integer
+{
+  bool neg;
+  uint64_t num;
+};
+
+struct codeview_subtype
+{
+  struct codeview_subtype *next;
+  uint16_t kind;
+
+  union
+  {
+    struct
+    {
+      char *name;
+      struct codeview_integer value;
+    } lf_enumerate;
+    struct
+    {
+      uint32_t type_num;
+    } lf_index;
+  };
+};
+
 struct codeview_custom_type
 {
   struct codeview_custom_type *next;
@@ -188,6 +218,20 @@ struct codeview_custom_type
       uint32_t base_type;
       uint16_t modifier;
     } lf_modifier;
+    struct
+    {
+      size_t length;
+      codeview_subtype *subtypes;
+      codeview_subtype *last_subtype;
+    } lf_fieldlist;
+    struct
+    {
+      uint16_t count;
+      uint16_t properties;
+      uint32_t underlying_type;
+      uint32_t fieldlist;
+      char *name;
+    } lf_enum;
   };
 };
 
@@ -978,6 +1022,292 @@ write_lf_modifier (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* Write a CodeView extensible integer.  If the value is non-negative and
+   < 0x8000, the value gets written directly as an uint16_t.  Otherwise, we
+   output two bytes for the integer type (LF_CHAR, LF_SHORT, ...), and the
+   actual value follows.  */
+
+static size_t
+write_cv_integer (codeview_integer *i)
+{
+  if (i->neg)
+    {
+      if (i->num <= 0x80)
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_CHAR);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (1, false), asm_out_file);
+	  fprint_whex (asm_out_file, -i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 3;
+	}
+      else if (i->num <= 0x8000)
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_SHORT);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, -i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 4;
+	}
+      else if (i->num <= 0x80000000)
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_LONG);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (4, false), asm_out_file);
+	  fprint_whex (asm_out_file, -i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 6;
+	}
+      else
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_QUADWORD);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (8, false), asm_out_file);
+	  fprint_whex (asm_out_file, -i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 10;
+	}
+    }
+  else
+    {
+      if (i->num <= 0x7fff)
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 2;
+	}
+      else if (i->num <= 0xffff)
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_USHORT);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 4;
+	}
+      else if (i->num <= 0xffffffff)
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_ULONG);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (4, false), asm_out_file);
+	  fprint_whex (asm_out_file, i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 6;
+	}
+      else
+	{
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_UQUADWORD);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (8, false), asm_out_file);
+	  fprint_whex (asm_out_file, i->num);
+	  putc ('\n', asm_out_file);
+
+	  return 10;
+	}
+    }
+}
+
+/* Return the extra size needed for an extensible integer.  */
+
+static size_t
+cv_integer_len (codeview_integer *i)
+{
+  if (i->neg)
+    {
+      if (i->num <= 0x80)
+	return sizeof (int8_t);
+      else if (i->num <= 0x8000)
+	return sizeof (int16_t);
+      else if (i->num <= 0x80000000)
+	return sizeof (int32_t);
+      else
+	return sizeof (int64_t);
+    }
+  else
+    {
+      if (i->num <= 0x7fff)
+	return 0;
+      else if (i->num <= 0xffff)
+	return sizeof (uint16_t);
+      else if (i->num <= 0xffffffff)
+	return sizeof (uint32_t);
+      else
+	return sizeof (uint64_t);
+    }
+}
+
+/* Write an LF_FIELDLIST type, which is a container for various subtypes.  This
+   has two uses: for the values in an enum, and for the member, operators etc.
+   for a struct, class, or union.  */
+
+static void
+write_lf_fieldlist (codeview_custom_type *t)
+{
+  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);
+
+  while (t->lf_fieldlist.subtypes)
+    {
+      codeview_subtype *v = t->lf_fieldlist.subtypes;
+      codeview_subtype *next = v->next;
+      size_t name_len, leaf_len;
+
+      switch (v->kind)
+	{
+	case LF_ENUMERATE:
+	  /* This is lf_enumerate in binutils and lfEnumerate in Microsoft's
+	     cvinfo.h:
+
+	    struct lf_enumerate
+	    {
+	      uint16_t kind;
+	      uint16_t attributes;
+	      uint16_t value;
+	      (then actual value if value >= 0x8000)
+	      char name[];
+	    } ATTRIBUTE_PACKED;
+	  */
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_ENUMERATE);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, CV_ACCESS_PUBLIC);
+	  putc ('\n', asm_out_file);
+
+	  leaf_len = 4 + write_cv_integer (&v->lf_enumerate.value);
+
+	  name_len = strlen (v->lf_enumerate.name) + 1;
+	  ASM_OUTPUT_ASCII (asm_out_file, v->lf_enumerate.name, name_len);
+
+	  leaf_len += name_len;
+	  write_cv_padding (4 - (leaf_len % 4));
+
+	  free (v->lf_enumerate.name);
+	  break;
+
+	case LF_INDEX:
+	  /* This is lf_index in binutils and lfIndex in Microsoft's cvinfo.h:
+
+	    struct lf_index
+	    {
+	      uint16_t kind;
+	      uint16_t padding;
+	      uint32_t index;
+	    } ATTRIBUTE_PACKED;
+	  */
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_INDEX);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, 0);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (4, false), asm_out_file);
+	  fprint_whex (asm_out_file, v->lf_index.type_num);
+	  putc ('\n', asm_out_file);
+
+	  break;
+	}
+
+      t->lf_fieldlist.subtypes = next;
+      free (v);
+    }
+
+  asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
+}
+
+/* Write an LF_ENUM type.  */
+
+static void
+write_lf_enum (codeview_custom_type *t)
+{
+  size_t name_len, leaf_len;
+
+  /* This is lf_enum in binutils and lfEnum in Microsoft's cvinfo.h:
+
+    struct lf_enum
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint16_t num_elements;
+      uint16_t properties;
+      uint32_t underlying_type;
+      uint32_t field_list;
+      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 (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_enum.count);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_enum.properties);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_enum.underlying_type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_enum.fieldlist);
+  putc ('\n', asm_out_file);
+
+  name_len = strlen (t->lf_enum.name) + 1;
+  ASM_OUTPUT_ASCII (asm_out_file, t->lf_enum.name, name_len);
+
+  leaf_len = 14 + name_len;
+  write_cv_padding (4 - (leaf_len % 4));
+
+  free (t->lf_enum.name);
+
+  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.  */
 
@@ -1003,6 +1333,14 @@ write_custom_types (void)
 	case LF_MODIFIER:
 	  write_lf_modifier (custom_types);
 	  break;
+
+	case LF_FIELDLIST:
+	  write_lf_fieldlist (custom_types);
+	  break;
+
+	case LF_ENUM:
+	  write_lf_enum (custom_types);
+	  break;
 	}
 
       free (custom_types);
@@ -1308,6 +1646,188 @@ get_type_num_volatile_type (dw_die_ref type)
   return ct->num;
 }
 
+/* Add a forward declaration for an enum.  This is legal from C++11 onwards.  */
+
+static uint32_t
+add_enum_forward_def (dw_die_ref type)
+{
+  codeview_custom_type *ct;
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_ENUM;
+
+  ct->lf_enum.count = 0;
+  ct->lf_enum.properties = CV_PROP_FWDREF;
+  ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type));
+  ct->lf_enum.fieldlist = 0;
+  ct->lf_enum.name = xstrdup (get_AT_string (type, DW_AT_name));
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
+/* Process a DW_TAG_enumeration_type DIE, adding an LF_FIELDLIST and an LF_ENUM
+   type, returning the number of the latter.  */
+
+static uint32_t
+get_type_num_enumeration_type (dw_die_ref type)
+{
+  dw_die_ref first_child;
+  codeview_custom_type *ct;
+  uint16_t count = 0;
+  uint32_t last_type;
+
+  if (get_AT_flag (type, DW_AT_declaration))
+    return add_enum_forward_def (type);
+
+  /* First, add an LF_FIELDLIST for the enum's values.  We don't need to worry
+     about deduplication here, as ld will take care of that for us.  If there's
+     a lot of entries, add more LF_FIELDLISTs with LF_INDEXes pointing to
+     the overflow lists.  */
+
+  first_child = dw_get_die_child (type);
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_FIELDLIST;
+  ct->lf_fieldlist.length = 0;
+  ct->lf_fieldlist.subtypes = NULL;
+  ct->lf_fieldlist.last_subtype = NULL;
+
+  if (first_child)
+    {
+      dw_die_ref c;
+
+      c = first_child;
+      do
+	{
+	  dw_attr_node *att;
+	  codeview_subtype *el;
+	  size_t el_len;
+
+	  c = dw_get_die_sib (c);
+
+	  if (dw_get_die_tag (c) != DW_TAG_enumerator)
+	    continue;
+
+	  att = get_AT (c, DW_AT_const_value);
+	  if (!att)
+	    continue;
+
+	  el = (codeview_subtype *) xmalloc (sizeof (*el));
+	  el->next = NULL;
+	  el->kind = LF_ENUMERATE;
+
+	  switch (AT_class (att))
+	    {
+	    case dw_val_class_unsigned_const:
+	    case dw_val_class_unsigned_const_implicit:
+	      el->lf_enumerate.value.neg = false;
+	      el->lf_enumerate.value.num = att->dw_attr_val.v.val_unsigned;
+	      break;
+
+	    case dw_val_class_const:
+	    case dw_val_class_const_implicit:
+	      if (att->dw_attr_val.v.val_int < 0)
+		{
+		  el->lf_enumerate.value.neg = true;
+		  el->lf_enumerate.value.num = -att->dw_attr_val.v.val_int;
+		}
+	      else
+		{
+		  el->lf_enumerate.value.neg = false;
+		  el->lf_enumerate.value.num = att->dw_attr_val.v.val_int;
+		}
+	      break;
+
+	    default:
+	      free (el);
+	      continue;
+	    }
+
+	  el->lf_enumerate.name = xstrdup (get_AT_string (c, DW_AT_name));
+
+	  el_len = 7 + strlen (el->lf_enumerate.name);
+	  el_len += cv_integer_len (&el->lf_enumerate.value);
+
+	  if (el_len % 4)
+	    el_len += 4 - (el_len % 4);
+
+	  if (ct->lf_fieldlist.length + el_len > MAX_FIELDLIST_SIZE)
+	    {
+	      codeview_subtype *idx;
+	      codeview_custom_type *ct2;
+
+	      idx = (codeview_subtype *) xmalloc (sizeof (*idx));
+	      idx->next = NULL;
+	      idx->kind = LF_INDEX;
+	      idx->lf_index.type_num = 0;
+
+	      ct->lf_fieldlist.last_subtype->next = idx;
+	      ct->lf_fieldlist.last_subtype = idx;
+
+	      ct2 = (codeview_custom_type *)
+		xmalloc (sizeof (codeview_custom_type));
+
+	      ct2->next = ct;
+	      ct2->kind = LF_FIELDLIST;
+	      ct2->lf_fieldlist.length = 0;
+	      ct2->lf_fieldlist.subtypes = NULL;
+	      ct2->lf_fieldlist.last_subtype = NULL;
+
+	      ct = ct2;
+	    }
+
+	  ct->lf_fieldlist.length += el_len;
+
+	  if (ct->lf_fieldlist.last_subtype)
+	    ct->lf_fieldlist.last_subtype->next = el;
+	  else
+	    ct->lf_fieldlist.subtypes = el;
+
+	  ct->lf_fieldlist.last_subtype = el;
+	  count++;
+	}
+      while (c != first_child);
+    }
+
+  while (ct)
+    {
+      codeview_custom_type *ct2;
+
+      ct2 = ct->next;
+      ct->next = NULL;
+
+      if (ct->lf_fieldlist.last_subtype->kind == LF_INDEX)
+	ct->lf_fieldlist.last_subtype->lf_index.type_num = last_type;
+
+      add_custom_type (ct);
+      last_type = ct->num;
+
+      ct = ct2;
+    }
+
+  /* Now add an LF_ENUM, pointing to the LF_FIELDLIST we just added.  */
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_ENUM;
+  ct->lf_enum.count = count;
+  ct->lf_enum.properties = 0;
+  ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type));
+  ct->lf_enum.fieldlist = last_type;
+  ct->lf_enum.name = xstrdup (get_AT_string (type, DW_AT_name));
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
 /* 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
@@ -1358,6 +1878,10 @@ get_type_num (dw_die_ref type)
       t->num = get_type_num_volatile_type (type);
       break;
 
+    case DW_TAG_enumeration_type:
+      t->num = get_type_num_enumeration_type (type);
+      break;
+
     default:
       t->num = 0;
       break;
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index d48cfbebc32..3f3695625c4 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -63,6 +63,23 @@ along with GCC; see the file COPYING3.  If not see
 /* Constants for type definitions.  */
 #define LF_MODIFIER		0x1001
 #define LF_POINTER		0x1002
+#define LF_FIELDLIST		0x1203
+#define LF_INDEX		0x1404
+#define LF_ENUMERATE		0x1502
+#define LF_ENUM			0x1507
+#define LF_CHAR			0x8000
+#define LF_SHORT		0x8001
+#define LF_USHORT		0x8002
+#define LF_LONG			0x8003
+#define LF_ULONG		0x8004
+#define LF_QUADWORD		0x8009
+#define LF_UQUADWORD		0x800a
+
+#define CV_ACCESS_PRIVATE	1
+#define CV_ACCESS_PROTECTED	2
+#define CV_ACCESS_PUBLIC	3
+
+#define CV_PROP_FWDREF		0x80
 
 /* Debug Format Interface.  Used in dwarf2out.cc.  */
 
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 07/11] Handle structs and classes for CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (5 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 06/11] Handle enums " Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-25  5:40   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 08/11] Handle unions " Mark Harmstone
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Translates DW_TAG_structure_type DIEs into LF_STRUCTURE symbols, and
DW_TAG_class_type DIEs into LF_CLASS symbols.

    gcc/
            * dwarf2codeview.cc
            (struct codeview_type): Add is_fwd_ref member.
            (struct codeview_subtype): Add lf_member to union.
            (struct codeview_custom_type): Add lf_structure to union.
            (struct codeview_deferred_type): New structure.
            (deferred_types, last_deferred_type): New variables.
            (get_type_num): Add new args to prototype.
            (write_lf_fieldlist): Handle LF_MEMBER subtypes.
            (write_lf_structure): New function.
            (write_custom_types): Call write_lf_structure.
            (get_type_num_pointer_type): Add in_struct argument.
            (get_type_num_const_type): Likewise.
            (get_type_num_volatile_type): Likewise.
            (add_enum_forward_def): Fix get_type_num call.
            (get_type_num_enumeration_type): Add in-struct argument.
            (add_deferred_type, flush_deferred_types): New functions.
            (add_struct_forward_def, get_type_num_struct): Likewise.
            (get_type_num): Handle self-referential structs.
            (add_variable): Fix get_type_num call.
            (codeview_debug_early_finish): Call flush_deferred_types.
            * dwarf2codeview.h (LF_CLASS, LF_STRUCTURE, LF_MEMBER): Define.
---
 gcc/dwarf2codeview.cc | 513 ++++++++++++++++++++++++++++++++++++++++--
 gcc/dwarf2codeview.h  |   3 +
 2 files changed, 493 insertions(+), 23 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 475a53573e9..9c6614f6297 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -158,6 +158,7 @@ struct codeview_type
 {
   dw_die_ref die;
   uint32_t num;
+  bool is_fwd_ref;
 };
 
 struct die_hasher : free_ptr_hash <codeview_type>
@@ -197,6 +198,13 @@ struct codeview_subtype
     {
       uint32_t type_num;
     } lf_index;
+    struct
+    {
+      uint16_t attributes;
+      uint32_t type;
+      codeview_integer offset;
+      char *name;
+    } lf_member;
   };
 };
 
@@ -232,9 +240,25 @@ struct codeview_custom_type
       uint32_t fieldlist;
       char *name;
     } lf_enum;
+    struct
+    {
+      uint16_t num_members;
+      uint16_t properties;
+      uint32_t field_list;
+      uint32_t derived_from;
+      uint32_t vshape;
+      codeview_integer length;
+      char *name;
+    } lf_structure;
   };
 };
 
+struct codeview_deferred_type
+{
+  struct codeview_deferred_type *next;
+  dw_die_ref type;
+};
+
 static unsigned int line_label_num;
 static unsigned int func_label_num;
 static unsigned int sym_label_num;
@@ -249,8 +273,9 @@ static uint32_t last_file_id;
 static codeview_symbol *sym, *last_sym;
 static hash_table<die_hasher> *types_htab;
 static codeview_custom_type *custom_types, *last_custom_type;
+static codeview_deferred_type *deferred_types, *last_deferred_type;
 
-static uint32_t get_type_num (dw_die_ref type);
+static uint32_t get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref);
 
 /* Record new line number against the current function.  */
 
@@ -1217,6 +1242,51 @@ write_lf_fieldlist (codeview_custom_type *t)
 	  free (v->lf_enumerate.name);
 	  break;
 
+	case LF_MEMBER:
+	  /* This is lf_member in binutils and lfMember in Microsoft's
+	     cvinfo.h:
+
+	    struct lf_member
+	    {
+	      uint16_t kind;
+	      uint16_t attributes;
+	      uint32_t type;
+	      uint16_t offset;
+	      char name[];
+	    } ATTRIBUTE_PACKED;
+	  */
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, LF_MEMBER);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (2, false), asm_out_file);
+	  fprint_whex (asm_out_file, v->lf_member.attributes);
+	  putc ('\n', asm_out_file);
+
+	  fputs (integer_asm_op (4, false), asm_out_file);
+	  fprint_whex (asm_out_file, v->lf_member.type);
+	  putc ('\n', asm_out_file);
+
+	  leaf_len = 8 + write_cv_integer (&v->lf_member.offset);
+
+	  if (v->lf_member.name)
+	    {
+	      name_len = strlen (v->lf_member.name) + 1;
+	      ASM_OUTPUT_ASCII (asm_out_file, v->lf_member.name, name_len);
+	    }
+	  else
+	    {
+	      name_len = 1;
+	      ASM_OUTPUT_ASCII (asm_out_file, "", name_len);
+	    }
+
+	  leaf_len += name_len;
+	  write_cv_padding (4 - (leaf_len % 4));
+
+	  free (v->lf_member.name);
+	  break;
+
 	case LF_INDEX:
 	  /* This is lf_index in binutils and lfIndex in Microsoft's cvinfo.h:
 
@@ -1308,6 +1378,82 @@ write_lf_enum (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* Write an LF_STRUCTURE or LF_CLASS type (the two have the same structure).  */
+
+static void
+write_lf_structure (codeview_custom_type *t)
+{
+  size_t name_len, leaf_len;
+
+  /* This is lf_class in binutils and lfClass in Microsoft's cvinfo.h:
+
+    struct lf_class
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint16_t num_members;
+      uint16_t properties;
+      uint32_t field_list;
+      uint32_t derived_from;
+      uint32_t vshape;
+      uint16_t length;
+      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 (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.num_members);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.properties);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.field_list);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.derived_from);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.vshape);
+  putc ('\n', asm_out_file);
+
+  leaf_len = 20 + write_cv_integer (&t->lf_structure.length);
+
+  if (t->lf_structure.name)
+    {
+      name_len = strlen (t->lf_structure.name) + 1;
+      ASM_OUTPUT_ASCII (asm_out_file, t->lf_structure.name, name_len);
+    }
+  else
+    {
+      static const char unnamed_struct[] = "<unnamed-tag>";
+
+      name_len = sizeof (unnamed_struct);
+      ASM_OUTPUT_ASCII (asm_out_file, unnamed_struct, name_len);
+    }
+
+  leaf_len += name_len;
+  write_cv_padding (4 - (leaf_len % 4));
+
+  free (t->lf_structure.name);
+
+  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.  */
 
@@ -1341,6 +1487,11 @@ write_custom_types (void)
 	case LF_ENUM:
 	  write_lf_enum (custom_types);
 	  break;
+
+	case LF_STRUCTURE:
+	case LF_CLASS:
+	  write_lf_structure (custom_types);
+	  break;
 	}
 
       free (custom_types);
@@ -1527,7 +1678,7 @@ add_custom_type (codeview_custom_type *ct)
    LF_POINTER type and return its number.  */
 
 static uint32_t
-get_type_num_pointer_type (dw_die_ref type)
+get_type_num_pointer_type (dw_die_ref type, bool in_struct)
 {
   uint32_t base_type_num, byte_size;
   dw_die_ref base_type;
@@ -1543,7 +1694,7 @@ get_type_num_pointer_type (dw_die_ref type)
   if (!base_type)
     return byte_size == 4 ? T_32PVOID : T_64PVOID;
 
-  base_type_num = get_type_num (base_type);
+  base_type_num = get_type_num (base_type, in_struct, false);
   if (base_type_num == 0)
     return 0;
 
@@ -1580,7 +1731,7 @@ get_type_num_pointer_type (dw_die_ref type)
    its number.  */
 
 static uint32_t
-get_type_num_const_type (dw_die_ref type)
+get_type_num_const_type (dw_die_ref type, bool in_struct)
 {
   dw_die_ref base_type;
   uint32_t base_type_num;
@@ -1602,7 +1753,7 @@ get_type_num_const_type (dw_die_ref type)
 	return 0;
     }
 
-  base_type_num = get_type_num (base_type);
+  base_type_num = get_type_num (base_type, in_struct, false);
   if (base_type_num == 0)
     return 0;
 
@@ -1625,12 +1776,13 @@ get_type_num_const_type (dw_die_ref type)
    returning its number.  */
 
 static uint32_t
-get_type_num_volatile_type (dw_die_ref type)
+get_type_num_volatile_type (dw_die_ref type, bool in_struct)
 {
   uint32_t base_type_num;
   codeview_custom_type *ct;
 
-  base_type_num = get_type_num (get_AT_ref (type, DW_AT_type));
+  base_type_num = get_type_num (get_AT_ref (type, DW_AT_type), in_struct,
+				false);
   if (base_type_num == 0)
     return 0;
 
@@ -1660,7 +1812,8 @@ add_enum_forward_def (dw_die_ref type)
 
   ct->lf_enum.count = 0;
   ct->lf_enum.properties = CV_PROP_FWDREF;
-  ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type));
+  ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type),
+					      false, false);
   ct->lf_enum.fieldlist = 0;
   ct->lf_enum.name = xstrdup (get_AT_string (type, DW_AT_name));
 
@@ -1673,7 +1826,7 @@ add_enum_forward_def (dw_die_ref type)
    type, returning the number of the latter.  */
 
 static uint32_t
-get_type_num_enumeration_type (dw_die_ref type)
+get_type_num_enumeration_type (dw_die_ref type, bool in_struct)
 {
   dw_die_ref first_child;
   codeview_custom_type *ct;
@@ -1819,7 +1972,8 @@ get_type_num_enumeration_type (dw_die_ref type)
   ct->kind = LF_ENUM;
   ct->lf_enum.count = count;
   ct->lf_enum.properties = 0;
-  ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type));
+  ct->lf_enum.underlying_type = get_type_num (get_AT_ref (type, DW_AT_type),
+					      in_struct, false);
   ct->lf_enum.fieldlist = last_type;
   ct->lf_enum.name = xstrdup (get_AT_string (type, DW_AT_name));
 
@@ -1828,6 +1982,292 @@ get_type_num_enumeration_type (dw_die_ref type)
   return ct->num;
 }
 
+/* Add a DIE to our deferred_types list.  This happens when we have a struct
+   with a pointer to a type that hasn't been defined yet, but which gets
+   defined later on.  */
+
+static void
+add_deferred_type (dw_die_ref type)
+{
+  codeview_deferred_type *def;
+
+  def = (codeview_deferred_type *) xmalloc (sizeof (codeview_deferred_type));
+
+  def->next = NULL;
+  def->type = type;
+
+  if (!deferred_types)
+    deferred_types = def;
+  else
+    last_deferred_type->next = def;
+
+  last_deferred_type = def;
+}
+
+/* Flush the contents of our deferred_types list.  This happens after everything
+   else has been written.  We call get_type_num to ensure that a type gets
+   added to custom_types, if it hasn't been already.  */
+
+static void
+flush_deferred_types (void)
+{
+  while (deferred_types)
+    {
+      codeview_deferred_type *next;
+
+      next = deferred_types->next;
+
+      get_type_num (deferred_types->type, false, true);
+
+      free (deferred_types);
+      deferred_types = next;
+    }
+
+  last_deferred_type = NULL;
+}
+
+/* Add a forward definition for a struct or class.  */
+
+static uint32_t
+add_struct_forward_def (dw_die_ref type)
+{
+  codeview_custom_type *ct;
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+
+  switch (dw_get_die_tag (type))
+    {
+    case DW_TAG_class_type:
+      ct->kind = LF_CLASS;
+      break;
+
+    case DW_TAG_structure_type:
+      ct->kind = LF_STRUCTURE;
+      break;
+
+    default:
+      break;
+    }
+
+  ct->lf_structure.num_members = 0;
+  ct->lf_structure.properties = CV_PROP_FWDREF;
+  ct->lf_structure.field_list = 0;
+  ct->lf_structure.derived_from = 0;
+  ct->lf_structure.vshape = 0;
+  ct->lf_structure.length.neg = false;
+  ct->lf_structure.length.num = 0;
+  ct->lf_structure.name = xstrdup (get_AT_string (type, DW_AT_name));
+
+  add_custom_type (ct);
+
+  if (!get_AT_flag (type, DW_AT_declaration))
+    add_deferred_type (type);
+
+  return ct->num;
+}
+
+/* Process a DW_TAG_structure_type or DW_TAG_class_type DIE, add an
+   LF_FIELDLIST and an LF_STRUCTURE / LF_CLASS type, and return the number of
+   the latter.  */
+
+static uint32_t
+get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref)
+{
+  dw_die_ref first_child;
+  codeview_custom_type *ct;
+  uint16_t num_members = 0;
+  uint32_t last_type;
+  const char *name;
+
+  if ((in_struct && get_AT_string (type, DW_AT_name))
+      || get_AT_flag (type, DW_AT_declaration))
+    {
+      *is_fwd_ref = true;
+      return add_struct_forward_def (type);
+    }
+
+  *is_fwd_ref = false;
+
+  /* First, add an LF_FIELDLIST for the structure's members.  We don't need to
+     worry about deduplication here, as ld will take care of that for us.
+     If there's a lot of entries, add more LF_FIELDLISTs with LF_INDEXes
+     pointing to the overflow lists.  */
+
+  first_child = dw_get_die_child (type);
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_FIELDLIST;
+  ct->lf_fieldlist.length = 0;
+  ct->lf_fieldlist.subtypes = NULL;
+  ct->lf_fieldlist.last_subtype = NULL;
+
+  if (first_child)
+    {
+      dw_die_ref c;
+
+      c = first_child;
+      do
+	{
+	  codeview_subtype *el;
+	  size_t el_len;
+
+	  c = dw_get_die_sib (c);
+
+	  if (dw_get_die_tag (c) != DW_TAG_member)
+	    continue;
+
+	  el = (codeview_subtype *) xmalloc (sizeof (*el));
+	  el->next = NULL;
+	  el->kind = LF_MEMBER;
+
+	  switch (get_AT_unsigned (c, DW_AT_accessibility))
+	    {
+	    case DW_ACCESS_private:
+	      el->lf_member.attributes = CV_ACCESS_PRIVATE;
+	      break;
+
+	    case DW_ACCESS_protected:
+	      el->lf_member.attributes = CV_ACCESS_PROTECTED;
+	      break;
+
+	    case DW_ACCESS_public:
+	      el->lf_member.attributes = CV_ACCESS_PUBLIC;
+	      break;
+
+	    /* Members in a C++ struct or union are public by default, members
+	      in a class are private.  */
+	    default:
+	      if (dw_get_die_tag (type) == DW_TAG_class_type)
+		el->lf_member.attributes = CV_ACCESS_PRIVATE;
+	      else
+		el->lf_member.attributes = CV_ACCESS_PUBLIC;
+	      break;
+	    }
+
+	  el->lf_member.type = get_type_num (get_AT_ref (c, DW_AT_type), true,
+					    false);
+	  el->lf_member.offset.neg = false;
+	  el->lf_member.offset.num = get_AT_unsigned (c,
+						      DW_AT_data_member_location);
+
+	  el_len = 11;
+	  el_len += cv_integer_len (&el->lf_member.offset);
+
+	  if (get_AT_string (c, DW_AT_name))
+	    {
+	      el->lf_member.name = xstrdup (get_AT_string (c, DW_AT_name));
+	      el_len += strlen (el->lf_member.name);
+	    }
+	  else
+	    {
+	      el->lf_member.name = NULL;
+	    }
+
+	  if (el_len % 4)
+	    el_len += 4 - (el_len % 4);
+
+	  /* Add an LF_INDEX subtype if everything's too big for one
+	     LF_FIELDLIST.  */
+
+	  if (ct->lf_fieldlist.length + el_len > MAX_FIELDLIST_SIZE)
+	    {
+	      codeview_subtype *idx;
+	      codeview_custom_type *ct2;
+
+	      idx = (codeview_subtype *) xmalloc (sizeof (*idx));
+	      idx->next = NULL;
+	      idx->kind = LF_INDEX;
+	      idx->lf_index.type_num = 0;
+
+	      ct->lf_fieldlist.last_subtype->next = idx;
+	      ct->lf_fieldlist.last_subtype = idx;
+
+	      ct2 = (codeview_custom_type *)
+		xmalloc (sizeof (codeview_custom_type));
+
+	      ct2->next = ct;
+	      ct2->kind = LF_FIELDLIST;
+	      ct2->lf_fieldlist.length = 0;
+	      ct2->lf_fieldlist.subtypes = NULL;
+	      ct2->lf_fieldlist.last_subtype = NULL;
+
+	      ct = ct2;
+	    }
+
+	  ct->lf_fieldlist.length += el_len;
+
+	  if (ct->lf_fieldlist.last_subtype)
+	    ct->lf_fieldlist.last_subtype->next = el;
+	  else
+	    ct->lf_fieldlist.subtypes = el;
+
+	  ct->lf_fieldlist.last_subtype = el;
+	  num_members++;
+	}
+      while (c != first_child);
+    }
+
+  while (ct)
+    {
+      codeview_custom_type *ct2;
+
+      ct2 = ct->next;
+      ct->next = NULL;
+
+      if (ct->lf_fieldlist.last_subtype->kind == LF_INDEX)
+	ct->lf_fieldlist.last_subtype->lf_index.type_num = last_type;
+
+      add_custom_type (ct);
+      last_type = ct->num;
+
+      ct = ct2;
+    }
+
+  /* Now add an LF_STRUCTURE / LF_CLASS, pointing to the LF_FIELDLIST we just
+     added.  */
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+
+  switch (dw_get_die_tag (type))
+    {
+    case DW_TAG_class_type:
+      ct->kind = LF_CLASS;
+      break;
+
+    case DW_TAG_structure_type:
+      ct->kind = LF_STRUCTURE;
+      break;
+
+    default:
+      break;
+    }
+
+  ct->lf_structure.num_members = num_members;
+  ct->lf_structure.properties = 0;
+  ct->lf_structure.field_list = last_type;
+  ct->lf_structure.derived_from = 0;
+  ct->lf_structure.vshape = 0;
+  ct->lf_structure.length.neg = false;
+  ct->lf_structure.length.num = get_AT_unsigned (type, DW_AT_byte_size);
+
+  name = get_AT_string (type, DW_AT_name);
+
+  if (name)
+    ct->lf_structure.name = xstrdup (name);
+  else
+    ct->lf_structure.name = NULL;
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
 /* 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
@@ -1835,9 +2275,11 @@ get_type_num_enumeration_type (dw_die_ref type)
    everything for us.  */
 
 static uint32_t
-get_type_num (dw_die_ref type)
+get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref)
 {
   codeview_type **slot, *t;
+  uint32_t num;
+  bool is_fwd_ref;
 
   if (!type)
     return 0;
@@ -1846,47 +2288,69 @@ get_type_num (dw_die_ref type)
     types_htab = new hash_table<die_hasher> (10);
 
   slot = types_htab->find_slot_with_hash (type, htab_hash_pointer (type),
-					  INSERT);
+					  NO_INSERT);
 
-  if (*slot)
+  if (slot && *slot && (!no_fwd_ref || !(*slot)->is_fwd_ref))
     return (*slot)->num;
 
-  t = (codeview_type *) xmalloc (sizeof (codeview_type));
-  t->die = type;
+  is_fwd_ref = false;
 
   switch (dw_get_die_tag (type))
     {
     case DW_TAG_base_type:
-      t->num = get_type_num_base_type (type);
+      num = get_type_num_base_type (type);
       break;
 
     case DW_TAG_typedef:
       /* FIXME - signed longs typedef'd as "HRESULT" should get their
 		 own type (T_HRESULT) */
-      t->num = get_type_num (get_AT_ref (type, DW_AT_type));
+      num = get_type_num (get_AT_ref (type, DW_AT_type), in_struct, false);
       break;
 
     case DW_TAG_pointer_type:
-      t->num = get_type_num_pointer_type (type);
+      num = get_type_num_pointer_type (type, in_struct);
       break;
 
     case DW_TAG_const_type:
-      t->num = get_type_num_const_type (type);
+      num = get_type_num_const_type (type, in_struct);
       break;
 
     case DW_TAG_volatile_type:
-      t->num = get_type_num_volatile_type (type);
+      num = get_type_num_volatile_type (type, in_struct);
       break;
 
     case DW_TAG_enumeration_type:
-      t->num = get_type_num_enumeration_type (type);
+      num = get_type_num_enumeration_type (type, in_struct);
+      break;
+
+    case DW_TAG_structure_type:
+    case DW_TAG_class_type:
+      num = get_type_num_struct (type, in_struct, &is_fwd_ref);
       break;
 
     default:
-      t->num = 0;
+      num = 0;
       break;
     }
 
+  /* Check hash table again, and account for the fact that self-referential
+     structs will have created a forward reference to themselves.  */
+
+  slot = types_htab->find_slot_with_hash (type, htab_hash_pointer (type),
+					  INSERT);
+
+  if (*slot && (*slot)->is_fwd_ref && !is_fwd_ref)
+    {
+      (*slot)->num = num;
+      (*slot)->is_fwd_ref = false;
+      return num;
+    }
+
+  t = (codeview_type *) xmalloc (sizeof (codeview_type));
+  t->die = type;
+  t->num = num;
+  t->is_fwd_ref = is_fwd_ref;
+
   *slot = t;
 
   return t->num;
@@ -1909,7 +2373,8 @@ add_variable (dw_die_ref die)
 
   s->next = NULL;
   s->kind = get_AT (die, DW_AT_external) ? S_GDATA32 : S_LDATA32;
-  s->data_symbol.type = get_type_num (get_AT_ref (die, DW_AT_type));
+  s->data_symbol.type = get_type_num (get_AT_ref (die, DW_AT_type), false,
+				      false);
   s->data_symbol.name = xstrdup (name);
   s->data_symbol.die = die;
 
@@ -1944,6 +2409,8 @@ codeview_debug_early_finish (dw_die_ref die)
       c = dw_get_die_sib (c);
     }
   while (c != first_child);
+
+  flush_deferred_types ();
 }
 
 #endif
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index 3f3695625c4..d4740247d93 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -66,7 +66,10 @@ along with GCC; see the file COPYING3.  If not see
 #define LF_FIELDLIST		0x1203
 #define LF_INDEX		0x1404
 #define LF_ENUMERATE		0x1502
+#define LF_CLASS		0x1504
+#define LF_STRUCTURE		0x1505
 #define LF_ENUM			0x1507
+#define LF_MEMBER		0x150d
 #define LF_CHAR			0x8000
 #define LF_SHORT		0x8001
 #define LF_USHORT		0x8002
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 08/11] Handle unions for CodeView.
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (6 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 07/11] Handle structs and classes " Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-25 23:29   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 09/11] Handle arrays " Mark Harmstone
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Translates DW_TAG_union_type DIEs into LF_UNION symbols.

    gcc/
            * dwarf2codeview.cc (write_lf_union): New function.
            (write_custom_types): Call write_lf_union.
            (add_struct_forward_def): Handle DW_TAG_union_type DIEs.
            (get_type_num_struct): Handle unions.
            (get_type_num): Handle DW_TAG_union_type DIEs.
            * dwarf2codeview.h (LF_UNION): Define.
---
 gcc/dwarf2codeview.cc | 91 ++++++++++++++++++++++++++++++++++++++++---
 gcc/dwarf2codeview.h  |  1 +
 2 files changed, 86 insertions(+), 6 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 9c6614f6297..9e3b64522b2 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -1454,6 +1454,72 @@ write_lf_structure (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* Write an LF_UNION type.  */
+
+static void
+write_lf_union (codeview_custom_type *t)
+{
+  size_t name_len, leaf_len;
+
+  /* This is lf_union in binutils and lfUnion in Microsoft's cvinfo.h:
+
+    struct lf_union
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint16_t num_members;
+      uint16_t properties;
+      uint32_t field_list;
+      uint16_t length;
+      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 (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.num_members);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.properties);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_structure.field_list);
+  putc ('\n', asm_out_file);
+
+  leaf_len = 12 + write_cv_integer (&t->lf_structure.length);
+
+  if (t->lf_structure.name)
+    {
+      name_len = strlen (t->lf_structure.name) + 1;
+      ASM_OUTPUT_ASCII (asm_out_file, t->lf_structure.name, name_len);
+    }
+  else
+    {
+      static const char unnamed_struct[] = "<unnamed-tag>";
+
+      name_len = sizeof (unnamed_struct);
+      ASM_OUTPUT_ASCII (asm_out_file, unnamed_struct, name_len);
+    }
+
+  leaf_len += name_len;
+  write_cv_padding (4 - (leaf_len % 4));
+
+  free (t->lf_structure.name);
+
+  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.  */
 
@@ -1492,6 +1558,10 @@ write_custom_types (void)
 	case LF_CLASS:
 	  write_lf_structure (custom_types);
 	  break;
+
+	case LF_UNION:
+	  write_lf_union (custom_types);
+	  break;
 	}
 
       free (custom_types);
@@ -2026,7 +2096,7 @@ flush_deferred_types (void)
   last_deferred_type = NULL;
 }
 
-/* Add a forward definition for a struct or class.  */
+/* Add a forward definition for a struct, class, or union.  */
 
 static uint32_t
 add_struct_forward_def (dw_die_ref type)
@@ -2047,6 +2117,10 @@ add_struct_forward_def (dw_die_ref type)
       ct->kind = LF_STRUCTURE;
       break;
 
+    case DW_TAG_union_type:
+      ct->kind = LF_UNION;
+      break;
+
     default:
       break;
     }
@@ -2068,9 +2142,9 @@ add_struct_forward_def (dw_die_ref type)
   return ct->num;
 }
 
-/* Process a DW_TAG_structure_type or DW_TAG_class_type DIE, add an
-   LF_FIELDLIST and an LF_STRUCTURE / LF_CLASS type, and return the number of
-   the latter.  */
+/* Process a DW_TAG_structure_type, DW_TAG_class_type, or DW_TAG_union_type
+   DIE, add an LF_FIELDLIST and an LF_STRUCTURE / LF_CLASS / LF_UNION type,
+   and return the number of the latter.  */
 
 static uint32_t
 get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref)
@@ -2227,8 +2301,8 @@ get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref)
       ct = ct2;
     }
 
-  /* Now add an LF_STRUCTURE / LF_CLASS, pointing to the LF_FIELDLIST we just
-     added.  */
+  /* Now add an LF_STRUCTURE / LF_CLASS / LF_UNION, pointing to the
+     LF_FIELDLIST we just added.  */
 
   ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
 
@@ -2244,6 +2318,10 @@ get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref)
       ct->kind = LF_STRUCTURE;
       break;
 
+    case DW_TAG_union_type:
+      ct->kind = LF_UNION;
+      break;
+
     default:
       break;
     }
@@ -2325,6 +2403,7 @@ get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref)
 
     case DW_TAG_structure_type:
     case DW_TAG_class_type:
+    case DW_TAG_union_type:
       num = get_type_num_struct (type, in_struct, &is_fwd_ref);
       break;
 
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index d4740247d93..e60fe86e673 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
 #define LF_ENUMERATE		0x1502
 #define LF_CLASS		0x1504
 #define LF_STRUCTURE		0x1505
+#define LF_UNION		0x1506
 #define LF_ENUM			0x1507
 #define LF_MEMBER		0x150d
 #define LF_CHAR			0x8000
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 09/11] Handle arrays for CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (7 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 08/11] Handle unions " Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-25 23:32   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 10/11] Handle bitfields " Mark Harmstone
  2024-06-18  0:17 ` [PATCH 11/11] Handle subroutine types in CodeView Mark Harmstone
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

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


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 10/11] Handle bitfields for CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (8 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 09/11] Handle arrays " Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-26  2:21   ` Jeff Law
  2024-06-18  0:17 ` [PATCH 11/11] Handle subroutine types in CodeView Mark Harmstone
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Translates structure members with DW_AT_data_bit_offset set in DWARF
into LF_BITFIELD symbols.

    gcc/
            * dwarf2codeview.cc
            (struct codeview_custom_type): Add lf_bitfield to union.
            (write_lf_bitfield): New function.
            (write_custom_types): Call write_lf_bitfield.
            (create_bitfield): New function.
            (get_type_num_struct): Handle bitfields.
            * dwarf2codeview.h (LF_BITFIELD): Define.
---
 gcc/dwarf2codeview.cc | 89 ++++++++++++++++++++++++++++++++++++++++++-
 gcc/dwarf2codeview.h  |  1 +
 2 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 3f1ce5577fc..06267639169 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -256,6 +256,12 @@ struct codeview_custom_type
       uint32_t index_type;
       codeview_integer length_in_bytes;
     } lf_array;
+    struct
+    {
+      uint32_t base_type;
+      uint8_t length;
+      uint8_t position;
+    } lf_bitfield;
   };
 };
 
@@ -1573,6 +1579,50 @@ write_lf_array (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* Write an LF_BITFIELD type.  */
+
+static void
+write_lf_bitfield (codeview_custom_type *t)
+{
+  /* This is lf_bitfield in binutils and lfBitfield in Microsoft's cvinfo.h:
+
+    struct lf_bitfield
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t base_type;
+      uint8_t length;
+      uint8_t position;
+    } 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_bitfield.base_type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (1, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_bitfield.length);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (1, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_bitfield.position);
+  putc ('\n', asm_out_file);
+
+  write_cv_padding (2);
+
+  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.  */
 
@@ -1619,6 +1669,10 @@ write_custom_types (void)
 	case LF_ARRAY:
 	  write_lf_array (custom_types);
 	  break;
+
+	case LF_BITFIELD:
+	  write_lf_bitfield (custom_types);
+	  break;
 	}
 
       free (custom_types);
@@ -2199,6 +2253,33 @@ add_struct_forward_def (dw_die_ref type)
   return ct->num;
 }
 
+/* Add an LF_BITFIELD type, returning its number.  DWARF represents bitfields
+   as members in a struct with a DW_AT_data_bit_offset attribute, whereas in
+   CodeView they're a distinct type.  */
+
+static uint32_t
+create_bitfield (dw_die_ref c)
+{
+  codeview_custom_type *ct;
+  uint32_t base_type;
+
+  base_type = get_type_num (get_AT_ref (c, DW_AT_type), true, false);
+  if (base_type == 0)
+    return 0;
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_BITFIELD;
+  ct->lf_bitfield.base_type = base_type;
+  ct->lf_bitfield.length = get_AT_unsigned (c, DW_AT_bit_size);
+  ct->lf_bitfield.position = get_AT_unsigned (c, DW_AT_data_bit_offset);
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
 /* Process a DW_TAG_structure_type, DW_TAG_class_type, or DW_TAG_union_type
    DIE, add an LF_FIELDLIST and an LF_STRUCTURE / LF_CLASS / LF_UNION type,
    and return the number of the latter.  */
@@ -2279,8 +2360,12 @@ get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref)
 	      break;
 	    }
 
-	  el->lf_member.type = get_type_num (get_AT_ref (c, DW_AT_type), true,
-					    false);
+	  if (get_AT (c, DW_AT_data_bit_offset))
+	    el->lf_member.type = create_bitfield (c);
+	  else
+	    el->lf_member.type = get_type_num (get_AT_ref (c, DW_AT_type),
+					       true, false);
+
 	  el->lf_member.offset.neg = false;
 	  el->lf_member.offset.num = get_AT_unsigned (c,
 						      DW_AT_data_member_location);
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index 70eed6bf2aa..70eae554b80 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -64,6 +64,7 @@ along with GCC; see the file COPYING3.  If not see
 #define LF_MODIFIER		0x1001
 #define LF_POINTER		0x1002
 #define LF_FIELDLIST		0x1203
+#define LF_BITFIELD		0x1205
 #define LF_INDEX		0x1404
 #define LF_ENUMERATE		0x1502
 #define LF_ARRAY		0x1503
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 11/11] Handle subroutine types in CodeView
  2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
                   ` (9 preceding siblings ...)
  2024-06-18  0:17 ` [PATCH 10/11] Handle bitfields " Mark Harmstone
@ 2024-06-18  0:17 ` Mark Harmstone
  2024-06-26  2:27   ` Jeff Law
  10 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-18  0:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Mark Harmstone

Translates DW_TAG_subroutine_type DIEs into LF_PROCEDURE symbols.

    gcc/
            * dwarf2codeview.cc
            (struct codeview_custom_type): Add lf_procedure and lf_arglist
                to union.
            (write_lf_procedure, write_lf_arglist): New functions.
            (write_custom_types): Call write_lf_procedure and
                write_lf_arglist.
            (get_type_num_subroutine_type): New function.
            (get_type_num): Handle DW_TAG_subroutine_type DIEs.
            * dwarf2codeview.h (LF_PROCEDURE, LF_ARGLIST): Define.
---
 gcc/dwarf2codeview.cc | 238 ++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2codeview.h  |   2 +
 2 files changed, 240 insertions(+)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 06267639169..e8ed3713480 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -262,6 +262,19 @@ struct codeview_custom_type
       uint8_t length;
       uint8_t position;
     } lf_bitfield;
+    struct
+    {
+      uint32_t return_type;
+      uint8_t calling_convention;
+      uint8_t attributes;
+      uint16_t num_parameters;
+      uint32_t arglist;
+    } lf_procedure;
+    struct
+    {
+      uint32_t num_entries;
+      uint32_t *args;
+    } lf_arglist;
   };
 };
 
@@ -1623,6 +1636,102 @@ write_lf_bitfield (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* Write an LF_PROCEDURE type.  Function pointers are implemented as pointers
+   to one of these.  */
+
+static void
+write_lf_procedure (codeview_custom_type *t)
+{
+  /* This is lf_procedure in binutils and lfProc in Microsoft's cvinfo.h:
+
+    struct lf_procedure
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t return_type;
+      uint8_t calling_convention;
+      uint8_t attributes;
+      uint16_t num_parameters;
+      uint32_t arglist;
+    } 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_procedure.return_type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (1, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_procedure.calling_convention);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (1, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_procedure.attributes);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (2, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_procedure.num_parameters);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_procedure.arglist);
+  putc ('\n', asm_out_file);
+
+  asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
+}
+
+/* Write an LF_ARGLIST type.  This is just a list of other types.  LF_PROCEDURE
+   entries point to one of these.  */
+
+static void
+write_lf_arglist (codeview_custom_type *t)
+{
+  /* This is lf_arglist in binutils and lfArgList in Microsoft's cvinfo.h:
+
+    struct lf_arglist
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t num_entries;
+      uint32_t args[];
+    } 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_arglist.num_entries);
+  putc ('\n', asm_out_file);
+
+  for (uint32_t i = 0; i < t->lf_arglist.num_entries; i++)
+    {
+      fputs (integer_asm_op (4, false), asm_out_file);
+      fprint_whex (asm_out_file, t->lf_arglist.args[i]);
+      putc ('\n', asm_out_file);
+    }
+
+  free (t->lf_arglist.args);
+
+  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.  */
 
@@ -1673,6 +1782,14 @@ write_custom_types (void)
 	case LF_BITFIELD:
 	  write_lf_bitfield (custom_types);
 	  break;
+
+	case LF_PROCEDURE:
+	  write_lf_procedure (custom_types);
+	  break;
+
+	case LF_ARGLIST:
+	  write_lf_arglist (custom_types);
+	  break;
 	}
 
       free (custom_types);
@@ -2488,6 +2605,123 @@ get_type_num_struct (dw_die_ref type, bool in_struct, bool *is_fwd_ref)
   return ct->num;
 }
 
+/* Process a DW_TAG_subroutine_type DIE, adding an LF_ARGLIST and an
+   LF_PROCEDURE type, and returning the number of the latter.  */
+
+static uint32_t
+get_type_num_subroutine_type (dw_die_ref type, bool in_struct)
+{
+  codeview_custom_type *ct;
+  uint32_t return_type, arglist_type;
+  uint16_t num_args;
+  dw_die_ref first_child;
+
+  /* Find the return type.  */
+
+  if (get_AT_ref (type, DW_AT_type))
+    {
+      return_type = get_type_num (get_AT_ref (type, DW_AT_type), in_struct,
+				  false);
+      if (return_type == 0)
+	return 0;
+    }
+  else
+    {
+      return_type = T_VOID;
+    }
+
+  /* Count the arguments.  */
+
+  first_child = dw_get_die_child (type);
+  num_args = 0;
+
+  if (first_child)
+    {
+      dw_die_ref c;
+
+      c = first_child;
+      do
+	{
+	  c = dw_get_die_sib (c);
+
+	  if (dw_get_die_tag (c) != DW_TAG_formal_parameter
+	      && dw_get_die_tag (c) != DW_TAG_unspecified_parameters)
+	    continue;
+
+	  num_args++;
+	}
+      while (c != first_child);
+    }
+
+  /* Create an LF_ARGLIST for the arguments.  If this is a duplicate, ld
+     will take care of this for us.  */
+
+  first_child = dw_get_die_child (type);
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_ARGLIST;
+  ct->lf_arglist.num_entries = num_args;
+
+  if (num_args > 0)
+    {
+      dw_die_ref c;
+      uint32_t *argptr;
+
+      ct->lf_arglist.args = (uint32_t *) xmalloc (sizeof (uint32_t) * num_args);
+      argptr = ct->lf_arglist.args;
+
+      c = first_child;
+      do
+	{
+	  c = dw_get_die_sib (c);
+
+	  switch (dw_get_die_tag (c))
+	    {
+	    case DW_TAG_formal_parameter:
+	      *argptr = get_type_num (get_AT_ref (c, DW_AT_type), in_struct,
+				      false);
+	      argptr++;
+	      break;
+
+	    case DW_TAG_unspecified_parameters:
+	      *argptr = 0;
+	      argptr++;
+	      break;
+
+	    default:
+	      break;
+	    }
+	}
+      while (c != first_child);
+    }
+  else
+    {
+      ct->lf_arglist.args = NULL;
+    }
+
+  add_custom_type (ct);
+
+  arglist_type = ct->num;
+
+  /* Finally, create an LF_PROCEDURE.  */
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_PROCEDURE;
+  ct->lf_procedure.return_type = return_type;
+  ct->lf_procedure.calling_convention = 0;
+  ct->lf_procedure.attributes = 0;
+  ct->lf_procedure.num_parameters = num_args;
+  ct->lf_procedure.arglist = arglist_type;
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
 /* Process a DW_TAG_array_type DIE, adding an LF_ARRAY type and returning its
    number.  */
 
@@ -2671,6 +2905,10 @@ get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref)
       num = get_type_num_array_type (type, in_struct);
       break;
 
+    case DW_TAG_subroutine_type:
+      num = get_type_num_subroutine_type (type, in_struct);
+      break;
+
     default:
       num = 0;
       break;
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index 70eae554b80..e6ad517bf28 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -63,6 +63,8 @@ along with GCC; see the file COPYING3.  If not see
 /* Constants for type definitions.  */
 #define LF_MODIFIER		0x1001
 #define LF_POINTER		0x1002
+#define LF_PROCEDURE		0x1008
+#define LF_ARGLIST		0x1201
 #define LF_FIELDLIST		0x1203
 #define LF_BITFIELD		0x1205
 #define LF_INDEX		0x1404
-- 
2.44.2


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 01/11] Output CodeView data about variables
  2024-06-18  0:17 ` [PATCH 01/11] Output CodeView data about variables Mark Harmstone
@ 2024-06-23 23:50   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-23 23:50 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Parse the DW_TAG_variable DIEs, and outputs S_GDATA32 (for global variables)
> and S_LDATA32 (static global variables) symbols into the .debug$S section.
> 
>      gcc/
>              * dwarf2codeview.cc (S_LDATA32, S_GDATA32): Define.
>              (struct codeview_symbol): New structure.
>              (sym, last_sym): New variables.
>              (write_data_symbol): New function.
>              (write_codeview_symbols): Call write_data_symbol.
>              (add_variable, codeview_debug_early_finish): New functions.
>              * dwarf2codeview.h (codeview_debug_early_finish): Prototype.
>              * dwarf2out.cc
>              (dwarf2out_early_finish): Call codeview_debug_early_finish.
Thanks.  I've pushed this to the trunk.

Just one question.  I note you use #defines for the various constants. 
Any reason not to use a const object?  At least with those you can print 
them in a debugger rather than having to look them up in the source code.

Just a thought.  Naturally I'll be working my way through the rest of 
this kit.

jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 02/11] Handle CodeView base types
  2024-06-18  0:17 ` [PATCH 02/11] Handle CodeView base types Mark Harmstone
@ 2024-06-24  0:18   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-24  0:18 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Adds a get_type_num function to translate type DIEs into CodeView
> numbers, along with a hash table for this.  For now we just deal with
> the base types (integers, Unicode chars, floats, and bools).
> 
>      gcc/
>              * dwarf2codeview.cc (struct codeview_type): New structure.
>              (struct die_hasher): Likewise.
>              (types_htab): New variable.
>              (codeview_debug_finish): Free types_htab if allocated.
>              (get_type_num_base_type, get_type_num): New function.
>              (add_variable): Call get_type_num.
>              * dwarf2codeview.h (T_CHAR, T_SHORT, T_LONG, T_QUAD): Define.
>              (T_UCHAR, T_USHORT, T_ULONG, T_UQUAD, T_BOOL08): Likewise.
>              (T_REAL32, T_REAL64, T_REAL80, T_REAL128, T_RCHAR): Likewise.
>              (T_WCHAR, T_INT4, T_UINT4, T_CHAR16, T_CHAR32, T_CHAR8): Likewise.
Thanks.  I've pushed this patch to the trunk.

jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 03/11] Handle typedefs for CodeView
  2024-06-18  0:17 ` [PATCH 03/11] Handle typedefs for CodeView Mark Harmstone
@ 2024-06-24  0:30   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-24  0:30 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
>      gcc/
>              * dwarf2codeview.cc (get_type_num): Handle typedefs.
Thanks.  I've pushed this to the trunk.

jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 04/11] Handle pointers for CodeView
  2024-06-18  0:17 ` [PATCH 04/11] Handle pointers " Mark Harmstone
@ 2024-06-24  3:31   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-24  3:31 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Translates DW_TAG_pointer_type DIEs into LF_POINTER symbols, which get
> output into the .debug$T section.
> 
>      gcc/
>              * dwarf2codeview.cc (FIRST_TYPE): Define.
>              (struct codeview_custom_type): New structure.
>              (custom_types, last_custom_type): New variables.
>              (get_type_num): Prototype.
>              (write_lf_pointer, write_custom_types): New functions.
>              (codeview_debug_finish): Call write_custom_types.
>              (add_custom_type, get_type_num_pointer_type): New functions.
>              (get_type_num): Handle DW_TAG_pointer_type DIEs.
>              * dwarf2codeview.h (T_VOID): Define.
>              (CV_POINTER_32, CV_POINTER_64): Likewise.
>              (T_32PVOID, T_64PVOID): Likewise.
>              (CV_PTR_NEAR32, CV_PTR64, LF_POINTER): Likewise.
Thanks.  I've pushed this to the trunk.

jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 05/11] Handle const and varible modifiers for CodeView
  2024-06-18  0:17 ` [PATCH 05/11] Handle const and varible modifiers " Mark Harmstone
@ 2024-06-24  3:39   ` Jeff Law
  2024-06-25  2:49     ` Mark Harmstone
  0 siblings, 1 reply; 25+ messages in thread
From: Jeff Law @ 2024-06-24  3:39 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Translate DW_TAG_const_type and DW_TAG_volatile_type DIEs into
> LF_MODIFIER symbols.
> 
>      gcc/
>              * dwarf2codeview.cc
>              (struct codeview_custom_type): Add lf_modifier to union.
>              (write_cv_padding, write_lf_modifier): New functions.
>              (write_custom_types): Call write_lf_modifier.
>              (get_type_num_const_type): New function.
>              (get_type_num_volatile_type): Likewise.
>              (get_type_num): Handle DW_TAG_const_type and
>                  DW_TAG_volatile_type DIEs.
>              * dwarf2codeview.h (MOD_const, MOD_volatile): Define.
>              (LF_MODIFIER): Likewise.
> ---

> @@ -903,6 +908,76 @@ write_lf_pointer (codeview_custom_type *t)
>     asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
>   }
>   
> +/* All CodeView type definitions have to be aligned to a four-byte boundary,
> +   so write some padding bytes if necessary.  These have to be specific values:
> +   f3, f2, f1.  */
Consider changing the magic numbers to a #define or const object or an 
enum as a follow-up.


> +
> +  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
So presumably you're freeing these objects elsewhere?  I see the free 
(custom_types), but I don' see where you free an subobjects.  Did I miss 
something?

I'll go ahead and commit, but please double check for memory leaks.

Jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 06/11] Handle enums for CodeView
  2024-06-18  0:17 ` [PATCH 06/11] Handle enums " Mark Harmstone
@ 2024-06-24  3:49   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-24  3:49 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Translates DW_TAG_enumeration_type DIEs into LF_ENUM symbols.
> 
>      gcc/
>              * dwarf2codeview.cc (MAX_FIELDLIST_SIZE): Define.
>              (struct codeview_integer): New structure.
>              (struct codeview_subtype): Likewise
>              (struct codeview_custom_type): Add lf_fieldlist and lf_enum
>                  to union.
>              (write_cv_integer, cv_integer_len): New functions.
>              (write_lf_fieldlist, write_lf_enum): Likewise.
>              (write_custom_types): Call write_lf_fieldlist and write_lf_enum.
>              (add_enum_forward_def): New function.
>              (get_type_num_enumeration_type): Likewise.
>              (get_type_num): Handle DW_TAG_enumeration_type DIEs.
>              * dwarf2codeview.h (LF_FIELDLIST, LF_INDEX, LF_ENUMERATE): Define.
>              (LF_ENUM, LF_CHAR, LF_SHORT, LF_USHORT, LF_LONG): Likewise.
>              (LF_ULONG, LF_QUADWORD, LF_UQUADWORD): Likewise.
>              (CV_ACCESS_PRIVATE, CV_ACCESS_PROTECTED): Likewise.
>              (CV_ACCESS_PUBLIC, CV_PROP_FWDREF): Likewise.
> ---
>   gcc/dwarf2codeview.cc | 524 ++++++++++++++++++++++++++++++++++++++++++
>   gcc/dwarf2codeview.h  |  17 ++
>   2 files changed, 541 insertions(+)
> 

> @@ -978,6 +1022,292 @@ write_lf_modifier (codeview_custom_type *t)
>     asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
>   }
>   
> +/* Write a CodeView extensible integer.  If the value is non-negative and
> +   < 0x8000, the value gets written directly as an uint16_t.  Otherwise, we
> +   output two bytes for the integer type (LF_CHAR, LF_SHORT, ...), and the
> +   actual value follows.  */
As a follow-up, can you include a brief description of the return value?

Pushed to the trunk.  Thanks!

jeff

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 05/11] Handle const and varible modifiers for CodeView
  2024-06-24  3:39   ` Jeff Law
@ 2024-06-25  2:49     ` Mark Harmstone
  2024-06-25  5:42       ` Jeff Law
  0 siblings, 1 reply; 25+ messages in thread
From: Mark Harmstone @ 2024-06-25  2:49 UTC (permalink / raw)
  To: Jeff Law, gcc-patches

On 24/6/24 04:39, Jeff Law wrote:
>>
> So presumably you're freeing these objects elsewhere?  I see the free (custom_types), but I don' see where you free an subobjects.  Did I miss something?
> 
> I'll go ahead and commit, but please double check for memory leaks.

Thanks Jeff. I just realized I wrote "varible" rather than "volatile" - ah well.

See patch 4 - write_custom_types loops through the custom_types linked list, and removes and frees the head until it's empty.

Mark

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 07/11] Handle structs and classes for CodeView
  2024-06-18  0:17 ` [PATCH 07/11] Handle structs and classes " Mark Harmstone
@ 2024-06-25  5:40   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-25  5:40 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Translates DW_TAG_structure_type DIEs into LF_STRUCTURE symbols, and
> DW_TAG_class_type DIEs into LF_CLASS symbols.
> 
>      gcc/
>              * dwarf2codeview.cc
>              (struct codeview_type): Add is_fwd_ref member.
>              (struct codeview_subtype): Add lf_member to union.
>              (struct codeview_custom_type): Add lf_structure to union.
>              (struct codeview_deferred_type): New structure.
>              (deferred_types, last_deferred_type): New variables.
>              (get_type_num): Add new args to prototype.
>              (write_lf_fieldlist): Handle LF_MEMBER subtypes.
>              (write_lf_structure): New function.
>              (write_custom_types): Call write_lf_structure.
>              (get_type_num_pointer_type): Add in_struct argument.
>              (get_type_num_const_type): Likewise.
>              (get_type_num_volatile_type): Likewise.
>              (add_enum_forward_def): Fix get_type_num call.
>              (get_type_num_enumeration_type): Add in-struct argument.
>              (add_deferred_type, flush_deferred_types): New functions.
>              (add_struct_forward_def, get_type_num_struct): Likewise.
>              (get_type_num): Handle self-referential structs.
>              (add_variable): Fix get_type_num call.
>              (codeview_debug_early_finish): Call flush_deferred_types.
>              * dwarf2codeview.h (LF_CLASS, LF_STRUCTURE, LF_MEMBER): Define.
Thanks.  I've pushed this to the trunk.
jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 05/11] Handle const and varible modifiers for CodeView
  2024-06-25  2:49     ` Mark Harmstone
@ 2024-06-25  5:42       ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-25  5:42 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/24/24 8:49 PM, Mark Harmstone wrote:
> On 24/6/24 04:39, Jeff Law wrote:
>>>
>> So presumably you're freeing these objects elsewhere?  I see the free 
>> (custom_types), but I don' see where you free an subobjects.  Did I 
>> miss something?
>>
>> I'll go ahead and commit, but please double check for memory leaks.
> 
> Thanks Jeff. I just realized I wrote "varible" rather than "volatile" - 
> ah well.
Trivially fixable with a follow-up patch.

> 
> See patch 4 - write_custom_types loops through the custom_types linked 
> list, and removes and frees the head until it's empty.
Thanks.  I suspected it was the walk down that list, but better to just 
ask the author to be sure :-)  Thanks.

jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 08/11] Handle unions for CodeView.
  2024-06-18  0:17 ` [PATCH 08/11] Handle unions " Mark Harmstone
@ 2024-06-25 23:29   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-25 23:29 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Translates DW_TAG_union_type DIEs into LF_UNION symbols.
> 
>      gcc/
>              * dwarf2codeview.cc (write_lf_union): New function.
>              (write_custom_types): Call write_lf_union.
>              (add_struct_forward_def): Handle DW_TAG_union_type DIEs.
>              (get_type_num_struct): Handle unions.
>              (get_type_num): Handle DW_TAG_union_type DIEs.
>              * dwarf2codeview.h (LF_UNION): Define.
Thanks.  I've pushed this to the trunk.

jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 09/11] Handle arrays for CodeView
  2024-06-18  0:17 ` [PATCH 09/11] Handle arrays " Mark Harmstone
@ 2024-06-25 23:32   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-25 23:32 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> 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.
Thanks.  I've pushed this to the trunk.
jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 10/11] Handle bitfields for CodeView
  2024-06-18  0:17 ` [PATCH 10/11] Handle bitfields " Mark Harmstone
@ 2024-06-26  2:21   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-26  2:21 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Translates structure members with DW_AT_data_bit_offset set in DWARF
> into LF_BITFIELD symbols.
> 
>      gcc/
>              * dwarf2codeview.cc
>              (struct codeview_custom_type): Add lf_bitfield to union.
>              (write_lf_bitfield): New function.
>              (write_custom_types): Call write_lf_bitfield.
>              (create_bitfield): New function.
>              (get_type_num_struct): Handle bitfields.
>              * dwarf2codeview.h (LF_BITFIELD): Define.
Thanks.  I've pushed this to the trunk.
jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 11/11] Handle subroutine types in CodeView
  2024-06-18  0:17 ` [PATCH 11/11] Handle subroutine types in CodeView Mark Harmstone
@ 2024-06-26  2:27   ` Jeff Law
  0 siblings, 0 replies; 25+ messages in thread
From: Jeff Law @ 2024-06-26  2:27 UTC (permalink / raw)
  To: Mark Harmstone, gcc-patches



On 6/17/24 6:17 PM, Mark Harmstone wrote:
> Translates DW_TAG_subroutine_type DIEs into LF_PROCEDURE symbols.
> 
>      gcc/
>              * dwarf2codeview.cc
>              (struct codeview_custom_type): Add lf_procedure and lf_arglist
>                  to union.
>              (write_lf_procedure, write_lf_arglist): New functions.
>              (write_custom_types): Call write_lf_procedure and
>                  write_lf_arglist.
>              (get_type_num_subroutine_type): New function.
>              (get_type_num): Handle DW_TAG_subroutine_type DIEs.
>              * dwarf2codeview.h (LF_PROCEDURE, LF_ARGLIST): Define.
THanks.  I've pushed this to the trunk.

That's the main patchkit.  Just minor follow-up items when you can get 
them done.

I think the bigger question here is whether or not you're likely to do 
significant additional work here or elsewhere in GCC.  If so, we should 
probably get you write privs.  If not, we can continue having myself or 
someone else handle committing patches for you.

Jeff


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2024-06-26  2:27 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-18  0:17 [PATCH 00/11] CodeView variables and type system Mark Harmstone
2024-06-18  0:17 ` [PATCH 01/11] Output CodeView data about variables Mark Harmstone
2024-06-23 23:50   ` Jeff Law
2024-06-18  0:17 ` [PATCH 02/11] Handle CodeView base types Mark Harmstone
2024-06-24  0:18   ` Jeff Law
2024-06-18  0:17 ` [PATCH 03/11] Handle typedefs for CodeView Mark Harmstone
2024-06-24  0:30   ` Jeff Law
2024-06-18  0:17 ` [PATCH 04/11] Handle pointers " Mark Harmstone
2024-06-24  3:31   ` Jeff Law
2024-06-18  0:17 ` [PATCH 05/11] Handle const and varible modifiers " Mark Harmstone
2024-06-24  3:39   ` Jeff Law
2024-06-25  2:49     ` Mark Harmstone
2024-06-25  5:42       ` Jeff Law
2024-06-18  0:17 ` [PATCH 06/11] Handle enums " Mark Harmstone
2024-06-24  3:49   ` Jeff Law
2024-06-18  0:17 ` [PATCH 07/11] Handle structs and classes " Mark Harmstone
2024-06-25  5:40   ` Jeff Law
2024-06-18  0:17 ` [PATCH 08/11] Handle unions " Mark Harmstone
2024-06-25 23:29   ` Jeff Law
2024-06-18  0:17 ` [PATCH 09/11] Handle arrays " Mark Harmstone
2024-06-25 23:32   ` Jeff Law
2024-06-18  0:17 ` [PATCH 10/11] Handle bitfields " Mark Harmstone
2024-06-26  2:21   ` Jeff Law
2024-06-18  0:17 ` [PATCH 11/11] Handle subroutine types in CodeView Mark Harmstone
2024-06-26  2:27   ` Jeff Law

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).