[2/3] Write LF_POINTER CodeView types for pointers to member functions or data

Message ID 20241102223625.22493-2-mark@harmstone.com
State Committed
Commit b0f4f556ea9f07d0b6fb6407ab25a193d27c806e
Headers
Series [1/3] Write LF_BCLASS records in CodeView struct definitions |

Checks

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

Commit Message

Mark Harmstone Nov. 2, 2024, 10:36 p.m. UTC
  Translate DW_TAG_ptr_to_member_type DIEs into special extended
LF_POINTER CodeView types.

gcc/
	* dwarf2codeview.cc (struct codeview_custom_type): Add new fields to
	lf_pointer struct in union.
	(write_lf_pointer): Write containing_class and ptr_to_mem_type if
	applicable.
	(get_type_num_subroutine_type): Write correct containing_class_type if
	this is a pointer to a member function.
	(get_type_num_ptr_to_member_type): New function.
	(get_type_num): Call get_type_num_ptr_to_member_type.
	* dwarf2codeview.h (CV_PTR_MODE_MASK, CV_PTR_MODE_PMEM): Define.
	(CV_PTR_MODE_PMFUNC, CV_PMTYPE_D_Single, CV_PMTYPE_F_Single): Likewise.
---
 gcc/dwarf2codeview.cc | 103 ++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2codeview.h  |   9 ++++
 2 files changed, 112 insertions(+)
  

Patch

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 722a54b9c4e..876057b5a8c 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -1270,6 +1270,8 @@  struct codeview_custom_type
     {
       uint32_t base_type;
       uint32_t attributes;
+      uint32_t containing_class;
+      uint16_t ptr_to_mem_type;
     } lf_pointer;
     struct
     {
@@ -3393,6 +3395,10 @@  write_lf_pointer (codeview_custom_type *t)
       uint16_t kind;
       uint32_t base_type;
       uint32_t attributes;
+      (following only if CV_PTR_MODE_PMEM or CV_PTR_MODE_PMFUNC in attributes)
+      uint32_t containing_class;
+      uint16_t ptr_to_mem_type;
+      uint16_t padding;
     } ATTRIBUTE_PACKED;
   */
 
@@ -3414,6 +3420,20 @@  write_lf_pointer (codeview_custom_type *t)
   fprint_whex (asm_out_file, t->lf_pointer.attributes);
   putc ('\n', asm_out_file);
 
+  if ((t->lf_pointer.attributes & CV_PTR_MODE_MASK) == CV_PTR_MODE_PMEM
+      || (t->lf_pointer.attributes & CV_PTR_MODE_MASK) == CV_PTR_MODE_PMFUNC)
+    {
+      fputs (integer_asm_op (4, false), asm_out_file);
+      fprint_whex (asm_out_file, t->lf_pointer.containing_class);
+      putc ('\n', asm_out_file);
+
+      fputs (integer_asm_op (2, false), asm_out_file);
+      fprint_whex (asm_out_file, t->lf_pointer.ptr_to_mem_type);
+      putc ('\n', asm_out_file);
+
+      write_cv_padding (2);
+    }
+
   asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num);
 }
 
@@ -5886,6 +5906,30 @@  get_type_num_subroutine_type (dw_die_ref type, bool in_struct,
       return_type = T_VOID;
     }
 
+  /* Handle pointer to member function.  */
+  if (containing_class_type == 0)
+    {
+      dw_die_ref obj_ptr = get_AT_ref (type, DW_AT_object_pointer);
+
+      if (obj_ptr)
+	{
+	  dw_die_ref obj_ptr_type = get_AT_ref (obj_ptr, DW_AT_type);
+
+	  if (obj_ptr_type
+	      && dw_get_die_tag (obj_ptr_type) == DW_TAG_pointer_type)
+	    {
+	      dw_die_ref cont_class = get_AT_ref (obj_ptr_type, DW_AT_type);
+
+	      if (dw_get_die_tag (cont_class) == DW_TAG_const_type)
+		cont_class = get_AT_ref (cont_class, DW_AT_type);
+
+	      containing_class_type = get_type_num (cont_class, in_struct,
+						    false);
+	      this_type = get_type_num (obj_ptr_type, in_struct, false);
+	    }
+	}
+    }
+
   /* Count the arguments.  */
 
   first_child = dw_get_die_child (type);
@@ -6121,6 +6165,61 @@  get_type_num_array_type (dw_die_ref type, bool in_struct)
   return element_type;
 }
 
+/* Translate a DW_TAG_ptr_to_member_type DIE, that is a pointer to member
+   function or field, into an LF_POINTER record.  */
+
+static uint32_t
+get_type_num_ptr_to_member_type (dw_die_ref type, bool in_struct)
+{
+  uint32_t base_type_num;
+  uint32_t containing_class;
+  dw_die_ref base_type;
+  codeview_custom_type *ct;
+
+  base_type = get_AT_ref (type, DW_AT_type);
+
+  base_type_num = get_type_num (base_type, in_struct, false);
+  if (base_type_num == 0)
+    return 0;
+
+  containing_class = get_type_num (get_AT_ref (type, DW_AT_containing_type),
+				   in_struct, false);
+
+  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 (TARGET_64BIT)
+    {
+      ct->lf_pointer.attributes = CV_PTR_64;
+      ct->lf_pointer.attributes |= 8 << 13;
+    }
+  else
+    {
+      ct->lf_pointer.attributes = CV_PTR_NEAR32;
+      ct->lf_pointer.attributes |= 4 << 13;
+    }
+
+  ct->lf_pointer.containing_class = containing_class;
+
+  if (base_type && dw_get_die_tag (base_type) == DW_TAG_subroutine_type)
+    {
+      ct->lf_pointer.attributes |= CV_PTR_MODE_PMFUNC;
+      ct->lf_pointer.ptr_to_mem_type = CV_PMTYPE_F_Single;
+    }
+  else
+    {
+      ct->lf_pointer.attributes |= CV_PTR_MODE_PMEM;
+      ct->lf_pointer.ptr_to_mem_type = CV_PMTYPE_D_Single;
+    }
+
+  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
@@ -6198,6 +6297,10 @@  get_type_num (dw_die_ref type, bool in_struct, bool no_fwd_ref)
       num = get_type_num_subroutine_type (type, in_struct, 0, 0, 0);
       break;
 
+    case DW_TAG_ptr_to_member_type:
+      num = get_type_num_ptr_to_member_type (type, in_struct);
+      break;
+
     default:
       num = 0;
       break;
diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h
index c631349640f..c895ef3e04c 100644
--- a/gcc/dwarf2codeview.h
+++ b/gcc/dwarf2codeview.h
@@ -55,9 +55,18 @@  along with GCC; see the file COPYING3.  If not see
 /* LF_POINTER attributes.  */
 #define CV_PTR_NEAR32		0x0a
 #define CV_PTR_64		0x0c
+
+/* enum CV_ptrmode_e in cvinfo.h, shifted by 5 for the lfPointerAttr bitfield */
+#define CV_PTR_MODE_MASK	0xe0
 #define CV_PTR_MODE_LVREF	0x20
+#define CV_PTR_MODE_PMEM	0x40
+#define CV_PTR_MODE_PMFUNC	0x60
 #define CV_PTR_MODE_RVREF	0x80
 
+/* enum CV_pmtype_e in in cvinfo.h */
+#define CV_PMTYPE_D_Single	0x01
+#define CV_PMTYPE_F_Single	0x05
+
 /* LF_MODIFIER values.  */
 #define MOD_const		0x1
 #define MOD_volatile		0x2