[20/24] pdbout: Output file and line number of type definitions.

Message ID 20210320162652.23346-20-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 | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/pdbout.h |  10 +++
 2 files changed, 217 insertions(+), 1 deletion(-)

-- 
2.26.2

Patch

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index dae5c1ef679..8dbd8f58a87 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -79,6 +79,7 @@  static struct pdb_func *funcs = NULL, *cur_func = NULL;
 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 *string_types = NULL;
 static struct pdb_type *arglist_types = NULL;
 static struct pdb_type *pointer_types = NULL;
 static struct pdb_type *proc_types = NULL;
@@ -1301,6 +1302,53 @@  write_procedure (struct pdb_proc *proc)
   fprintf (asm_out_file, "\t.short\t0\n");	// padding
 }
 
+/* Output lfStringId structure. */
+static void
+write_string_id (struct pdb_type *t)
+{
+  size_t string_len = strlen ((const char *) t->data);
+  size_t len = 9 + string_len, align;
+
+  if (len % 4 != 0)
+    align = 4 - (len % 4);
+  else
+    align = 0;
+
+  len += align;
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+	   (uint16_t) (len - sizeof (uint16_t)));
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_STRING_ID);
+  fprintf (asm_out_file, "\t.long\t0\n");
+  ASM_OUTPUT_ASCII (asm_out_file, (const char *) t->data, string_len + 1);
+
+  if (align == 3)
+    fprintf (asm_out_file, "\t.byte\t0xf3\n");
+
+  if (align >= 2)
+    fprintf (asm_out_file, "\t.byte\t0xf2\n");
+
+  if (align >= 1)
+    fprintf (asm_out_file, "\t.byte\t0xf1\n");
+}
+
+/* Output lfUdtSrcLine structure, describing on which line in a file a
+ * type is defined. The linker transforms this into a lfUdtModSrcLine
+ * structure (LF_UDT_MOD_SRC_LINE), which also adds details of the
+ * "module" (i.e. object file). */
+static void
+write_udt_src_line (struct pdb_udt_src_line *t)
+{
+  fprintf (asm_out_file, "\t.short\t0xe\n");
+  fprintf (asm_out_file, "\t.short\t0x%x\n", LF_UDT_SRC_LINE);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", t->type ? t->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n");	// padding
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+	   t->source_file ? t->source_file->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n");	// padding
+  fprintf (asm_out_file, "\t.long\t0x%x\n", t->line);
+}
+
 /* Output lfModifier structure, representing a const or volatile version
  * of an existing type. */
 static void
@@ -1372,6 +1420,14 @@  write_type (struct pdb_type *t)
       write_procedure ((struct pdb_proc *) t->data);
       break;
 
+    case LF_STRING_ID:
+      write_string_id (t);
+      break;
+
+    case LF_UDT_SRC_LINE:
+      write_udt_src_line ((struct pdb_udt_src_line *) t->data);
+      break;
+
     case LF_MODIFIER:
       write_modifier ((struct pdb_modifier *) t->data);
       break;
@@ -2029,6 +2085,7 @@  find_type_bitfield (struct pdb_type *underlying_type, unsigned int size,
   type->tree = NULL;
   type->next = type->next2 = NULL;
   type->id = 0;
+  type->udt_src_line = NULL;
 
   bf = (struct pdb_bitfield *) type->data;
 
@@ -2081,6 +2138,7 @@  add_struct_forward_declaration (tree t, const char *name)
   strtype->tree = NULL;
   strtype->next = strtype->next2 = NULL;
   strtype->id = 0;
+  strtype->udt_src_line = NULL;
 
   str = (struct pdb_struct *) strtype->data;
   str->count = 0;
@@ -2195,6 +2253,7 @@  add_type_fieldlist (struct pdb_type *t)
 
   t->next = t->next2 = NULL;
   t->id = 0;
+  t->udt_src_line = NULL;
 
   if (last_entry)
     last_entry->next2 = t;
@@ -2459,6 +2518,7 @@  find_type_struct (tree t, bool is_union)
 
   strtype->next = strtype->next2 = NULL;
   strtype->id = 0;
+  strtype->udt_src_line = NULL;
 
   str = (struct pdb_struct *) strtype->data;
   str->count = num_entries;
@@ -2539,6 +2599,7 @@  find_type_array (tree t)
   arrtype->tree = t;
   arrtype->next = arrtype->next2 = NULL;
   arrtype->id = 0;
+  arrtype->udt_src_line = NULL;
 
   arr = (struct pdb_array *) arrtype->data;
   arr->type = type;
@@ -2607,6 +2668,7 @@  add_arglist_type (struct pdb_type *t)
 
   t->next = NULL;
   t->next2 = NULL;
+  t->udt_src_line = NULL;
   t->id = 0;
 
   if (last_type)
@@ -2725,6 +2787,7 @@  find_type_enum (tree t)
   enumtype->tree = t;
   enumtype->next = enumtype->next2 = NULL;
   enumtype->id = 0;
+  enumtype->udt_src_line = NULL;
 
   en = (struct pdb_enum *) enumtype->data;
   en->count = num_entries;
@@ -2798,6 +2861,7 @@  find_type_pointer (tree t)
   ptrtype->tree = t;
   ptrtype->next = ptrtype->next2 = NULL;
   ptrtype->id = 0;
+  ptrtype->udt_src_line = NULL;
 
   ptr = (struct pdb_pointer *) ptrtype->data;
   ptr->type = type;
@@ -2925,6 +2989,7 @@  find_type_function (tree t)
   proctype->tree = t;
   proctype->next = proctype->next2 = NULL;
   proctype->id = 0;
+  proctype->udt_src_line = NULL;
 
   proc = (struct pdb_proc *) proctype->data;
 
@@ -2990,6 +3055,7 @@  find_type_modifier (tree t)
   type->tree = t;
   type->next = type->next2 = NULL;
   type->id = 0;
+  type->udt_src_line = NULL;
 
   mod = (struct pdb_modifier *) type->data;
 
@@ -3037,6 +3103,7 @@  add_builtin_type (tree t, uint16_t id)
   type->tree = t;
   type->next = type->next2 = NULL;
   type->id = id;
+  type->udt_src_line = NULL;
 
   if (last_type)
     last_type->next = type;
@@ -3328,6 +3395,84 @@  find_type (tree t)
     }
 }
 
+/* Add a string as a type. This is only used by add_udt_src_line_type,
+ * which uses it to deduplicate source filenames. */
+static struct pdb_type *
+add_string_type (const char *s)
+{
+  struct pdb_type *type, *t, *last_string = NULL;
+  size_t len = strlen (s);
+
+  t = string_types;
+  while (t)
+    {
+      if (!strcmp (s, (char *) t->data))
+	return t;
+
+      last_string = t;
+      t = t->next2;
+    }
+
+  type =
+    (struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) + len + 1);
+  type->cv_type = LF_STRING_ID;
+  type->tree = NULL;
+  type->next = type->next2 = NULL;
+  type->udt_src_line = NULL;
+  type->id = 0;
+
+  memcpy (type->data, s, len + 1);
+
+  if (last_string)
+    last_string->next2 = type;
+  else
+    string_types = type;
+
+  if (last_type)
+    last_type->next = type;
+  else
+    types = type;
+
+  last_type = type;
+
+  return type;
+}
+
+/* Add a pdb_udt_src_line fake type to the type list, which records the file
+ * and line number where an actual type is defined.
+ * The linker will transform this into a LF_UDT_MOD_SRC_LINE, which also
+ * records the object file. */
+static void
+add_udt_src_line_type (struct pdb_type *ref_type,
+		       struct pdb_type *source_file, uint32_t line)
+{
+  struct pdb_type *type;
+  struct pdb_udt_src_line *pusl;
+
+  type =
+    (struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) +
+				 sizeof (struct pdb_udt_src_line));
+  type->cv_type = LF_UDT_SRC_LINE;
+  type->tree = NULL;
+  type->next = type->next2 = NULL;
+  type->udt_src_line = NULL;
+  type->id = 0;
+
+  pusl = (struct pdb_udt_src_line *) type->data;
+  pusl->type = ref_type;
+  pusl->source_file = source_file;
+  pusl->line = line;
+
+  if (last_type)
+    last_type->next = type;
+  else
+    types = type;
+
+  last_type = type;
+
+  ref_type->udt_src_line = type;
+}
+
 inline hashval_t
 alias_hasher::hash (alias_hasher::compare_type tree)
 {
@@ -3344,7 +3489,9 @@  alias_hasher::equal (const value_type type, compare_type tree)
 static void
 pdbout_type_decl (tree t, int local ATTRIBUTE_UNUSED)
 {
-  struct pdb_type *type;
+  struct pdb_type *string_type, *type;
+  struct pdb_source_file *psf;
+  expanded_location xloc;
 
   /* We need to record the typedefs to ensure e.g. that Windows'
    * LPWSTR gets mapped to wchar_t* rather than uint16_t*.
@@ -3455,6 +3602,65 @@  pdbout_type_decl (tree t, int local ATTRIBUTE_UNUSED)
 	  }
 	}
     }
+
+  if (!DECL_SOURCE_LOCATION (t) || type->udt_src_line)
+    return;
+
+  xloc = expand_location (DECL_SOURCE_LOCATION (t));
+
+  if (!xloc.file)
+    return;
+
+  // don't create LF_UDT_SRC_LINE entry for anonymous types
+
+  switch (type->cv_type)
+    {
+    case LF_STRUCTURE:
+    case LF_CLASS:
+    case LF_UNION:
+      {
+	struct pdb_struct *str = (struct pdb_struct *) type->data;
+
+	if (!str->name)
+	  return;
+
+	break;
+      }
+
+    case LF_ENUM:
+      {
+	struct pdb_enum *en = (struct pdb_enum *) type->data;
+
+	if (!en->name)
+	  return;
+
+	break;
+      }
+
+    default:
+      return;
+    }
+
+  string_type = NULL;
+
+  // add filename as LF_STRING_ID, so linker puts it into string table
+
+  psf = source_files;
+  while (psf)
+    {
+      if (!strcmp (psf->name, xloc.file))
+	{
+	  string_type = add_string_type (psf->name + strlen (psf->name) + 1);
+	  break;
+	}
+
+      psf = psf->next;
+    }
+
+  // add LF_UDT_SRC_LINE entry, which linker transforms
+  // into LF_UDT_MOD_SRC_LINE
+
+  add_udt_src_line_type (type, string_type, xloc.line);
 }
 
 #ifndef _WIN32
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index e12f1cf21a0..2b97ac83999 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -45,6 +45,8 @@ 
 #define LF_UNION			0x1506
 #define LF_ENUM				0x1507
 #define LF_MEMBER			0x150d
+#define LF_STRING_ID			0x1605
+#define LF_UDT_SRC_LINE			0x1606
 #define LF_CHAR				0x8000
 #define LF_SHORT			0x8001
 #define LF_USHORT			0x8002
@@ -270,6 +272,13 @@  struct pdb_proc
   struct pdb_type *arg_list;
 };
 
+struct pdb_udt_src_line
+{
+  struct pdb_type *type;
+  struct pdb_type *source_file;
+  uint32_t line;
+};
+
 struct pdb_type
 {
   struct pdb_type *next;
@@ -277,6 +286,7 @@  struct pdb_type
   uint16_t id;
   tree_node *tree;
   uint16_t cv_type;
+  struct pdb_type *udt_src_line;
   uint8_t data[1];
 };