If recording the definition of a struct member function, write an
LF_MFUNC_ID type rather than an LF_FUNC_ID. This links directly to the
struct type, rather than to an LF_STRING_ID with its name.

gcc/
        * dwarf2codeview.cc (enum cv_leaf_type): Add LF_MFUNC_ID.
        (write_lf_mfunc_id): New function.
        (add_lf_func_id): New function.
        (add_lf_mfunc_id): New function.
        (add_function): Call add_lf_func_id or add_lf_mfunc_id.
---
 gcc/dwarf2codeview.cc | 150 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 137 insertions(+), 13 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 1987575985a..6142431655b 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -112,6 +112,7 @@ enum cv_leaf_type {
   LF_METHOD = 0x150f,
   LF_ONEMETHOD = 0x1511,
   LF_FUNC_ID = 0x1601,
+  LF_MFUNC_ID = 0x1602,
   LF_STRING_ID = 0x1605,
   LF_CHAR = 0x8000,
   LF_SHORT = 0x8001,
@@ -4293,6 +4294,56 @@ write_lf_func_id (codeview_custom_type *t)
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
+/* Write an LF_MFUNC_ID type, which is the version of LF_FUNC_ID for struct
+   functions.  Instead of an LF_STRING_ID for the parent scope, we write the
+   type number of the parent struct.  */
+
+static void
+write_lf_mfunc_id (codeview_custom_type *t)
+{
+  size_t name_len;
+
+  /* This is lf_mfunc_id in binutils and lfMFuncId in Microsoft's cvinfo.h:
+
+    struct lf_mfunc_id
+    {
+      uint16_t size;
+      uint16_t kind;
+      uint32_t parent_type;
+      uint32_t function_type;
+      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_mfunc_id.parent_type);
+  putc ('\n', asm_out_file);
+
+  fputs (integer_asm_op (4, false), asm_out_file);
+  fprint_whex (asm_out_file, t->lf_mfunc_id.function_type);
+  putc ('\n', asm_out_file);
+
+  name_len = strlen (t->lf_mfunc_id.name) + 1;
+
+  ASM_OUTPUT_ASCII (asm_out_file, t->lf_mfunc_id.name, name_len);
+
+  write_cv_padding (4 - (name_len % 4));
+
+  free (t->lf_mfunc_id.name);
+
+  asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
+}
+
 /* Write an LF_STRING_ID type, which provides a deduplicated string that other
    types can reference.  */
 
@@ -4523,6 +4574,10 @@ write_custom_types (void)
          write_lf_func_id (custom_types);
          break;
 
+       case LF_MFUNC_ID:
+         write_lf_mfunc_id (custom_types);
+         break;
+
        case LF_STRING_ID:
          write_lf_string_id (custom_types);
          break;
@@ -6190,21 +6245,13 @@ get_scope_string_id (dw_die_ref die)
   return ret;
 }
 
-/* Process a DW_TAG_subprogram DIE, and add an S_GPROC32_ID or S_LPROC32_ID
-   symbol for this.  */
+/* Add an LF_FUNC_ID type and return its number (see write_lf_func_id).  */
 
-static void
-add_function (dw_die_ref die)
+static uint32_t
+add_lf_func_id (dw_die_ref die, const char *name)
 {
+  uint32_t function_type, scope_type;
   codeview_custom_type *ct;
-  const char *name = get_AT_string (die, DW_AT_name);
-  uint32_t function_type, func_id_type, scope_type;
-  codeview_symbol *s;
-
-  if (!name)
-    return;
-
-  /* Add an LF_FUNC_ID type for this function.  */
 
   function_type = get_type_num_subroutine_type (die, false, 0, 0, 0);
   scope_type = get_scope_string_id (die);
@@ -6219,7 +6266,84 @@ add_function (dw_die_ref die)
 
   add_custom_type (ct);
 
-  func_id_type = ct->num;
+  return ct->num;
+}
+
+/* Add an LF_MFUNC_ID type and return its number (see write_lf_mfunc_id).  */
+
+static uint32_t
+add_lf_mfunc_id (dw_die_ref die, const char *name)
+{
+  uint32_t function_type = 0, parent_type;
+  codeview_custom_type *ct;
+  dw_die_ref spec = get_AT_ref (die, DW_AT_specification);
+
+  parent_type = get_type_num (dw_get_die_parent (spec), false, false);
+
+  if (types_htab)
+    {
+      codeview_type **slot;
+
+      slot = types_htab->find_slot_with_hash (spec, htab_hash_pointer (spec),
+                                             NO_INSERT);
+
+      if (slot && *slot)
+       function_type = (*slot)->num;
+    }
+
+  if (function_type == 0)
+    {
+      function_type = get_type_num_subroutine_type (die, false, parent_type,
+                                                   0, 0);
+    }
+
+  ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type));
+
+  ct->next = NULL;
+  ct->kind = LF_MFUNC_ID;
+  ct->lf_mfunc_id.parent_type = parent_type;
+  ct->lf_mfunc_id.function_type = function_type;
+  ct->lf_mfunc_id.name = xstrdup (name);
+
+  add_custom_type (ct);
+
+  return ct->num;
+}
+
+/* Process a DW_TAG_subprogram DIE, and add an S_GPROC32_ID or S_LPROC32_ID
+   symbol for this.  */
+
+static void
+add_function (dw_die_ref die)
+{
+  const char *name = get_AT_string (die, DW_AT_name);
+  uint32_t func_id_type;
+  codeview_symbol *s;
+  dw_die_ref spec = get_AT_ref (die, DW_AT_specification);
+  bool do_mfunc_id = false;
+
+  if (!name)
+    return;
+
+  if (spec && dw_get_die_parent (spec))
+    {
+      switch (dw_get_die_tag (dw_get_die_parent (spec)))
+       {
+       case DW_TAG_class_type:
+       case DW_TAG_structure_type:
+       case DW_TAG_union_type:
+         do_mfunc_id = true;
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  if (do_mfunc_id)
+    func_id_type = add_lf_mfunc_id (die, name);
+  else
+    func_id_type = add_lf_func_id (die, name);
 
   /* Add an S_GPROC32_ID / S_LPROC32_ID symbol.  */
 
-- 
2.44.2

Reply via email to