[09/24] pdbout: Output information about pointers.

Message ID 20210320162652.23346-9-mark@harmstone.com
State New
Headers show
Series
  • [01/24] Add -gcodeview debugging option
Related show

Commit Message

Mark Harmstone March 20, 2021, 4:26 p.m.
---
 gcc/pdbout.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++---
 gcc/pdbout.h |  36 ++++++++++++++
 2 files changed, 161 insertions(+), 6 deletions(-)

-- 
2.26.2

Patch

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index 64f7c1d71bc..08bb14364e5 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -76,6 +76,7 @@  static struct pdb_block *cur_block = NULL;
 static struct pdb_global_var *global_vars = NULL;
 static struct pdb_type *types = NULL, *last_type = NULL;
 static struct pdb_type *arglist_types = NULL;
+static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
 static struct pdb_source_file *source_files = NULL, *last_source_file = NULL;
 static uint32_t source_file_string_offset = 1;
@@ -803,6 +804,17 @@  free_type (struct pdb_type *t)
   free (t);
 }
 
+/* Output a lfPointer structure. */
+static void
+write_pointer (struct pdb_pointer *ptr)
+{
+  fprintf (asm_out_file, "\t.short\t0xa\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_POINTER);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", ptr->type ? ptr->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n");	// padding
+  fprintf (asm_out_file, "\t.long\t0x%x\n", ptr->attr.num);
+}
+
 /* Output a lfArgList structure, describing the arguments that a
  * procedure expects. */
 static void
@@ -857,6 +869,13 @@  write_type (struct pdb_type *t)
 {
   switch (t->cv_type)
     {
+    case LF_POINTER:
+      if (t->id < FIRST_TYPE_NUM)	// pointer to builtin
+	return;
+
+      write_pointer ((struct pdb_pointer *) t->data);
+      break;
+
     case LF_ARGLIST:
       write_arglist ((struct pdb_arglist *) t->data);
       break;
@@ -910,13 +929,38 @@  number_types (void)
 	  continue;
 	}
 
-      t->id = type_num;
-      type_num++;
-
-      if (type_num == 0)	// overflow
+      switch (t->cv_type)
 	{
-	  fprintf (stderr, "too many CodeView types\n");
-	  xexit (1);
+	case LF_POINTER:
+	  {
+	    struct pdb_pointer *ptr = (struct pdb_pointer *) t->data;
+
+	    // pointers to builtins have their own constants
+	    if (ptr->type && ptr->type->id != 0 && ptr->type->id < 0x100)
+	      {
+		if (ptr->attr.s.ptrtype == CV_PTR_NEAR32)
+		  {
+		    t->id = (CV_TM_NPTR32 << 8) | ptr->type->id;
+		    break;
+		  }
+		else if (ptr->attr.s.ptrtype == CV_PTR_64)
+		  {
+		    t->id = (CV_TM_NPTR64 << 8) | ptr->type->id;
+		    break;
+		  }
+	      }
+	    [[fallthrough]];
+	  }
+
+	default:
+	  t->id = type_num;
+	  type_num++;
+
+	  if (type_num == 0)	// overflow
+	    {
+	      fprintf (stderr, "too many CodeView types\n");
+	      xexit (1);
+	    }
 	}
 
       t = t->next;
@@ -1072,6 +1116,77 @@  add_arglist_type (struct pdb_type *t)
   return t;
 }
 
+/* Given a pointer type t, allocate a new pdb_type and add it to the
+ * type list. */
+static struct pdb_type *
+find_type_pointer (tree t)
+{
+  struct pdb_type *ptrtype, *t2, *last_entry = NULL, *type;
+  struct pdb_pointer *ptr, v;
+  unsigned int size = TREE_INT_CST_ELT (TYPE_SIZE (t), 0) / 8;
+  struct pdb_type **slot;
+
+  type = find_type (TREE_TYPE (t));
+
+  if (!type)
+    return NULL;
+
+  v.attr.num = 0;
+
+  v.attr.s.size = size;
+
+  if (size == 8)
+    v.attr.s.ptrtype = CV_PTR_64;
+  else if (size == 4)
+    v.attr.s.ptrtype = CV_PTR_NEAR32;
+
+  if (TREE_CODE (t) == REFERENCE_TYPE)
+    v.attr.s.ptrmode =
+      TYPE_REF_IS_RVALUE (t) ? CV_PTR_MODE_RVREF : CV_PTR_MODE_LVREF;
+
+  t2 = pointer_types;
+  while (t2)
+    {
+      ptr = (struct pdb_pointer *) t2->data;
+
+      if (ptr->type == type && ptr->attr.num == v.attr.num)
+	return t2;
+
+      last_entry = t2;
+      t2 = t2->next2;
+    }
+
+  ptrtype =
+    (struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
+				 sizeof (struct pdb_pointer));
+  ptrtype->cv_type = LF_POINTER;
+  ptrtype->tree = t;
+  ptrtype->next = ptrtype->next2 = NULL;
+  ptrtype->id = 0;
+
+  ptr = (struct pdb_pointer *) ptrtype->data;
+  ptr->type = type;
+  ptr->attr.num = v.attr.num;
+
+  if (last_entry)
+    last_entry->next2 = ptrtype;
+  else
+    pointer_types = ptrtype;
+
+  if (last_type)
+    last_type->next = ptrtype;
+  else
+    types = ptrtype;
+
+  last_type = ptrtype;
+
+  slot =
+    tree_hash_table.find_slot_with_hash (t, htab_hash_pointer (t), INSERT);
+  *slot = ptrtype;
+
+  return ptrtype;
+}
+
 /* Given a function type t, allocate a new pdb_type and add it to the
  * type list. */
 static struct pdb_type *
@@ -1478,6 +1593,10 @@  find_type (tree t)
 
   switch (TREE_CODE (t))
     {
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      return find_type_pointer (t);
+
     case FUNCTION_TYPE:
     case METHOD_TYPE:
       return find_type_function (t);
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index b9e56a66069..a660728158e 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -21,6 +21,7 @@ 
 #define GCC_PDBOUT_H 1
 
 #define S_END				0x0006
+#define LF_POINTER			0x1002
 #define LF_PROCEDURE			0x1008
 #define S_BLOCK32			0x1103
 #define S_REGISTER			0x1106
@@ -124,6 +125,41 @@  struct pdb_global_var
   struct pdb_type *type;
 };
 
+// from CV_ptrtype_e in cvdump
+#define CV_PTR_NEAR32		0x0a
+#define CV_PTR_64		0x0c
+
+// from CV_ptrmode_e in cvdump
+#define CV_PTR_MODE_PTR		0x0
+#define CV_PTR_MODE_LVREF	0x1
+#define CV_PTR_MODE_PMEM	0x2
+#define CV_PTR_MODE_PMFUNC	0x3
+#define CV_PTR_MODE_RVREF	0x4
+
+struct pdb_pointer
+{
+  struct pdb_type *type;
+  union
+  {
+    struct
+    {
+      uint32_t ptrtype:5;
+      uint32_t ptrmode:3;
+      uint32_t isflat32:1;
+      uint32_t isvolatile:1;
+      uint32_t isconst:1;
+      uint32_t isunaligned:1;
+      uint32_t isrestrict:1;
+      uint32_t size:6;
+      uint32_t ismocom:1;
+      uint32_t islref:1;
+      uint32_t isrref:1;
+      uint32_t unused:10;
+    } s;
+    uint32_t num;
+  } attr;
+};
+
 struct pdb_arglist
 {
   unsigned int count;