[11/11] Handle subroutine types in CodeView

Message ID 20240618001713.24034-12-mark@harmstone.com
State Committed
Commit 01f8b1002147c08f206a058a6d1f7bfb006aa324
Headers
Series CodeView variables and type system |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed

Commit Message

Mark Harmstone June 18, 2024, 12:17 a.m. UTC
  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(+)
  

Comments

Jeff Law June 26, 2024, 2:27 a.m. UTC | #1
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
  

Patch

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