---
 gcc/pdbout.c | 417 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 gcc/pdbout.h |  89 +++++++++++
 2 files changed, 504 insertions(+), 2 deletions(-)

diff --git a/gcc/pdbout.c b/gcc/pdbout.c
index e8f39bb64ea..feaab37cc37 100644
--- a/gcc/pdbout.c
+++ b/gcc/pdbout.c
@@ -25,13 +25,37 @@
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "varasm.h"
 #include "tree.h"
 #include "debug.h"
 #include "pdbout.h"
+#include "output.h"
+#include "target.h"
+
+static void pdbout_finish (const char *filename);
+static void pdbout_late_global_decl (tree var);
+
+static struct pdb_type *find_type (tree t);
+
+static struct pdb_global_var *global_vars = NULL;
+static struct pdb_type *types = NULL, *last_type = NULL;
+static hash_table <pdb_type_tree_hasher> tree_hash_table (31);
+static struct pdb_type *byte_type, *signed_byte_type, *wchar_type,
+  *char16_type, *uint16_type, *int16_type, *char32_type, *uint32_type,
+  *int32_type, *uint64_type, *int64_type, *uint128_type, *int128_type,
+  *long_type, *ulong_type, *hresult_type;
+static struct pdb_type *float16_type, *float32_type, *float48_type,
+  *float64_type, *float80_type, *float128_type;
+static struct pdb_type *bool8_type, *bool16_type, *bool32_type, *bool64_type,
+  *bool128_type;
+static struct pdb_type *complex16_type, *complex32_type, *complex48_type,
+  *complex64_type, *complex80_type, *complex128_type;
+static struct pdb_type *void_type, *nullptr_type;
+static bool builtins_initialized = false;
 
 const struct gcc_debug_hooks pdb_debug_hooks = {
   debug_nothing_charstar,      /* init */
-  debug_nothing_charstar,      /* finish */
+  pdbout_finish,
   debug_nothing_charstar,      /* early_finish */
   debug_nothing_void,          /* assembly_start */
   debug_nothing_int_charstar,  /* define */
@@ -51,7 +75,7 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   debug_nothing_tree,          /* register_main_translation_unit */
   debug_nothing_tree,          /* function_decl */
   debug_nothing_tree,          /* early_global_decl */
-  debug_nothing_tree,          /* late_global_decl */
+  pdbout_late_global_decl,
   debug_nothing_tree_int,      /* type_decl */
   debug_nothing_tree_tree_tree_bool_bool,      /* imported_module_or_decl */
   debug_false_tree_charstarstar_uhwistar,      /* die_ref_for_decl */
@@ -68,3 +92,392 @@ const struct gcc_debug_hooks pdb_debug_hooks = {
   0,                           /* start_end_main_source_file */
   TYPE_SYMTAB_IS_ADDRESS       /* tree_type_symtab_field */
 };
+
+/* Output DATASYM32 structure, describing a global variable: either
+ * one with file-level scope (S_LDATA32) or global scope (S_GDATA32). */
+static void
+pdbout_data32 (struct pdb_global_var *v)
+{
+  size_t name_len = strlen (v->name);
+  uint16_t len;
+
+  // Outputs DATASYM32 struct
+
+  len = 15 + name_len;
+
+  if (len % 4 != 0)
+    len += 4 - (len % 4);
+
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+          (uint16_t) (len - sizeof (uint16_t)));       // reclen
+  fprintf (asm_out_file, "\t.short\t0x%x\n",
+          v->public_flag ? S_GDATA32 : S_LDATA32);
+  fprintf (asm_out_file, "\t.short\t0x%x\n", v->type ? v->type->id : 0);
+  fprintf (asm_out_file, "\t.short\t0\n");
+
+  fprintf (asm_out_file, "\t.secrel32\t");     // off
+  ASM_OUTPUT_LABELREF (asm_out_file, v->asm_name);
+  fprintf (asm_out_file, "\n");
+  fprintf (asm_out_file, "\t.secidx\t");       // section
+  ASM_OUTPUT_LABELREF (asm_out_file, v->asm_name);
+  fprintf (asm_out_file, "\n");
+
+  ASM_OUTPUT_ASCII (asm_out_file, v->name, name_len + 1);
+
+  fprintf (asm_out_file, "\t.balign\t4\n");
+}
+
+/* Output the .debug$S section, which has everything except the
+ * type definitions (global variables, functions, string table,
+ * file checksums, line numbers).
+ * The linker will extract this section from all the object
+ * files, remove any duplicate data, resolve all addresses,
+ * and output the resulting data into a PDB file. The section's
+ * marked as "ndr", so even if the linker doesn't understand it,
+ * the section won't make its way into final binary. */
+static void
+write_pdb_section (void)
+{
+  fprintf (asm_out_file, "\t.section\t.debug$S, \"ndr\"\n");
+  fprintf (asm_out_file, "\t.long\t0x%x\n", CV_SIGNATURE_C13);
+  fprintf (asm_out_file, "\t.long\t0x%x\n", DEBUG_S_SYMBOLS);
+  fprintf (asm_out_file, "\t.long\t[.Lsymend]-[.Lsymstart]\n");
+
+  fprintf (asm_out_file, ".Lsymstart:\n");
+
+  while (global_vars)
+    {
+      struct pdb_global_var *n;
+
+      pdbout_data32 (global_vars);
+
+      n = global_vars->next;
+
+      if (global_vars->name)
+       free (global_vars->name);
+
+      if (global_vars->asm_name)
+       free (global_vars->asm_name);
+
+      free (global_vars);
+
+      global_vars = n;
+    }
+
+  fprintf (asm_out_file, ".Lsymend:\n");
+}
+
+/* We've finished compilation - output the .debug$S section
+ * to the asm file. */
+static void
+pdbout_finish (const char *filename ATTRIBUTE_UNUSED)
+{
+  write_pdb_section ();
+}
+
+/* We've been passed a late global declaration, i.e. a global variable -
+ * allocate a pdb_global_var struct and add it to the list of globals. */
+static void
+pdbout_late_global_decl (tree var)
+{
+  struct pdb_global_var *v;
+
+  if (TREE_CODE (var) != VAR_DECL)
+    return;
+
+  if (!DECL_ASSEMBLER_NAME_RAW (var))
+    return;
+
+  // We take care of static variables in functions separately
+  if (DECL_CONTEXT (var) && TREE_CODE (DECL_CONTEXT (var)) == FUNCTION_DECL)
+    return;
+
+  if (!TREE_ASM_WRITTEN (var) || DECL_IGNORED_P (var))
+    return;
+
+  v = (struct pdb_global_var *) xmalloc (sizeof (struct pdb_global_var));
+
+  v->next = global_vars;
+  v->name = xstrdup (IDENTIFIER_POINTER (DECL_NAME (var)));
+  v->asm_name = xstrdup (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME_RAW (var)));
+  v->public_flag = TREE_PUBLIC (var);
+  v->type = find_type (TREE_TYPE (var));
+
+  global_vars = v;
+}
+
+inline hashval_t
+pdb_type_tree_hasher::hash (pdb_type_tree_hasher::compare_type tree)
+{
+  return htab_hash_pointer (tree);
+}
+
+inline bool
+pdb_type_tree_hasher::equal (const value_type type, compare_type tree)
+{
+  return type->tree == tree;
+}
+
+static struct pdb_type *
+add_builtin_type (tree t, uint16_t id)
+{
+  struct pdb_type *type, **slot;
+
+  type = (struct pdb_type *) xmalloc (offsetof (struct pdb_type, data));
+  type->cv_type = 0;
+  type->tree = t;
+  type->next = type->next2 = NULL;
+  type->id = id;
+
+  if (last_type)
+    last_type->next = type;
+  else
+    types = type;
+
+  last_type = type;
+
+  if (t)
+    {
+      slot =
+       tree_hash_table.find_slot_with_hash (t, htab_hash_pointer (t),
+                                            INSERT);
+      *slot = type;
+    }
+
+  return type;
+}
+
+/* Initialize the builtin types, ones that we won't output: the integers,
+ * the floats, the bools, etc. Pointers to these are also counted as
+ * predefined types, but we take care of these in number_types. */
+static void
+add_builtin_types (void)
+{
+  add_builtin_type (char_type_node, CV_BUILTIN_TYPE_NARROW_CHARACTER);
+  add_builtin_type (signed_char_type_node, CV_BUILTIN_TYPE_SIGNED_CHARACTER);
+  add_builtin_type (unsigned_char_type_node,
+                   CV_BUILTIN_TYPE_UNSIGNED_CHARACTER);
+  add_builtin_type (short_integer_type_node, CV_BUILTIN_TYPE_INT16SHORT);
+  add_builtin_type (short_unsigned_type_node, CV_BUILTIN_TYPE_UINT16SHORT);
+  long_type =
+    add_builtin_type (long_integer_type_node, CV_BUILTIN_TYPE_INT32LONG);
+  ulong_type =
+    add_builtin_type (long_unsigned_type_node, CV_BUILTIN_TYPE_UINT32LONG);
+  add_builtin_type (long_long_integer_type_node, CV_BUILTIN_TYPE_INT64QUAD);
+  add_builtin_type (long_long_unsigned_type_node, CV_BUILTIN_TYPE_UINT64QUAD);
+
+  byte_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_BYTE);
+  signed_byte_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_SBYTE);
+  wchar_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_WIDE_CHARACTER);
+  char16_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_CHARACTER16);
+  uint16_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_UINT16);
+  int16_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_INT16);
+  char32_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_CHARACTER32);
+  uint32_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_UINT32);
+  int32_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_INT32);
+  uint64_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_UINT64);
+  int64_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_INT64);
+  uint128_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_UINT128);
+  int128_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_INT128);
+  hresult_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_HRESULT);
+
+  float16_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_FLOAT16);
+  float32_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_FLOAT32);
+  float48_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_FLOAT48);
+  float64_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_FLOAT64);
+  float80_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_FLOAT80);
+  float128_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_FLOAT128);
+
+  bool8_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_BOOLEAN8);
+  bool16_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_BOOLEAN16);
+  bool32_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_BOOLEAN32);
+  bool64_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_BOOLEAN64);
+  bool128_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_BOOLEAN128);
+
+  complex16_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_COMPLEX16);
+  complex32_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_COMPLEX32);
+  complex48_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_COMPLEX48);
+  complex64_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_COMPLEX64);
+  complex80_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_COMPLEX80);
+  complex128_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_COMPLEX128);
+
+  void_type = add_builtin_type (NULL, CV_BUILTIN_TYPE_VOID);
+  nullptr_type =
+    add_builtin_type (NULL, (CV_TM_NPTR << 8) | CV_BUILTIN_TYPE_VOID);
+
+  builtins_initialized = true;
+}
+
+/* Resolve a type t to a pdb_type struct. */
+static struct pdb_type *
+find_type (tree t)
+{
+  struct pdb_type *type;
+
+  if (!builtins_initialized)
+    add_builtin_types ();
+
+  if (!t)
+    return NULL;
+
+  // search through existing types
+
+  type = tree_hash_table.find_with_hash (t, pdb_type_tree_hasher::hash (t));
+
+  if (type)
+    return type;
+
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_TYPE:
+      {
+       unsigned int size;
+
+       size = TREE_INT_CST_ELT (TYPE_SIZE (t), 0);
+
+       switch (size)
+         {
+         case 8:
+           return TYPE_UNSIGNED (t) ? byte_type : signed_byte_type;
+
+         case 16:
+           if (TYPE_IDENTIFIER (t)
+               && IDENTIFIER_POINTER (TYPE_IDENTIFIER (t))
+               && !strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (t)),
+                           "wchar_t"))
+             return wchar_type;
+           else if (TYPE_IDENTIFIER (t)
+                    && IDENTIFIER_POINTER (TYPE_IDENTIFIER (t))
+                    && !strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (t)),
+                                "char16_t"))
+             return char16_type;
+           else
+             return TYPE_UNSIGNED (t) ? uint16_type : int16_type;
+
+         case 32:
+           if (TYPE_IDENTIFIER (t)
+               && IDENTIFIER_POINTER (TYPE_IDENTIFIER (t))
+               && !strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (t)),
+                           "char32_t"))
+             return char32_type;
+           else
+             return TYPE_UNSIGNED (t) ? uint32_type : int32_type;
+
+         case 64:
+           return TYPE_UNSIGNED (t) ? uint64_type : int64_type;
+
+         case 128:
+           return TYPE_UNSIGNED (t) ? uint128_type : int128_type;
+
+         default:
+           return NULL;
+         }
+      }
+
+    case REAL_TYPE:
+      {
+       unsigned int size = TREE_INT_CST_ELT (TYPE_SIZE (t), 0);
+
+       switch (size)
+         {
+         case 16:
+           return float16_type;
+
+         case 32:
+           return float32_type;
+
+         case 48:
+           return float48_type;
+
+         case 64:
+           return float64_type;
+
+         case 80:
+           return float80_type;
+
+         case 128:
+           return float128_type;
+
+         default:
+           return NULL;
+         }
+      }
+
+    case BOOLEAN_TYPE:
+      {
+       unsigned int size = TREE_INT_CST_ELT (TYPE_SIZE (t), 0);
+
+       switch (size)
+         {
+         case 8:
+           return bool8_type;
+
+         case 16:
+           return bool16_type;
+
+         case 32:
+           return bool32_type;
+
+         case 64:
+           return bool64_type;
+
+         case 128:
+           return bool128_type;
+
+         default:
+           return NULL;
+         }
+      }
+
+    case COMPLEX_TYPE:
+      {
+       unsigned int size = TREE_INT_CST_ELT (TYPE_SIZE (t), 0);
+
+       switch (size)
+         {
+         case 16:
+           return complex16_type;
+
+         case 32:
+           return complex32_type;
+
+         case 48:
+           return complex48_type;
+
+         case 64:
+           return complex64_type;
+
+         case 80:
+           return complex80_type;
+
+         case 128:
+           return complex128_type;
+
+         default:
+           return NULL;
+         }
+      }
+
+    case VOID_TYPE:
+      return void_type;
+
+    case NULLPTR_TYPE:
+      return nullptr_type;
+
+    default:
+      break;
+    }
+
+  if (TYPE_MAIN_VARIANT (t) != t)
+    {
+      type =
+       tree_hash_table.find_with_hash (TYPE_MAIN_VARIANT (t),
+                                       pdb_type_tree_hasher::
+                                       hash (TYPE_MAIN_VARIANT (t)));
+
+      if (type)
+       return type;
+    }
+
+    return NULL;
+}
diff --git a/gcc/pdbout.h b/gcc/pdbout.h
index f957cd5eca1..e3430793ee7 100644
--- a/gcc/pdbout.h
+++ b/gcc/pdbout.h
@@ -20,4 +20,93 @@
 #ifndef GCC_PDBOUT_H
 #define GCC_PDBOUT_H 1
 
+#define S_LDATA32                      0x110c
+#define S_GDATA32                      0x110d
+
+/* Format version as of MSVC 7 */
+#define CV_SIGNATURE_C13       4
+
+#define DEBUG_S_SYMBOLS                        0xf1
+
+struct pdb_global_var
+{
+  struct pdb_global_var *next;
+  char *name;
+  char *asm_name;
+  unsigned int public_flag;
+  struct pdb_type *type;
+};
+
+struct pdb_type
+{
+  struct pdb_type *next;
+  struct pdb_type *next2;
+  uint16_t id;
+  tree_node *tree;
+  uint16_t cv_type;
+  uint8_t data[1];
+};
+
+#define CV_BUILTIN_TYPE_VOID                   0x0003
+#define CV_BUILTIN_TYPE_HRESULT                        0x0008
+#define CV_BUILTIN_TYPE_SIGNED_CHARACTER       0x0010
+#define CV_BUILTIN_TYPE_INT16SHORT             0x0011
+#define CV_BUILTIN_TYPE_INT32LONG              0x0012
+#define CV_BUILTIN_TYPE_INT64QUAD              0x0013
+#define CV_BUILTIN_TYPE_UINT64QUAD             0x0023
+#define CV_BUILTIN_TYPE_UNSIGNED_CHARACTER     0x0020
+#define CV_BUILTIN_TYPE_UINT16SHORT            0x0021
+#define CV_BUILTIN_TYPE_UINT32LONG             0x0022
+#define CV_BUILTIN_TYPE_BOOLEAN8               0x0030
+#define CV_BUILTIN_TYPE_BOOLEAN16              0x0031
+#define CV_BUILTIN_TYPE_BOOLEAN32              0x0032
+#define CV_BUILTIN_TYPE_BOOLEAN64              0x0033
+#define CV_BUILTIN_TYPE_BOOLEAN128             0x0034
+#define CV_BUILTIN_TYPE_FLOAT16                        0x0046
+#define CV_BUILTIN_TYPE_FLOAT32                        0x0040
+#define CV_BUILTIN_TYPE_FLOAT48                        0x0044
+#define CV_BUILTIN_TYPE_FLOAT64                        0x0041
+#define CV_BUILTIN_TYPE_FLOAT80                        0x0042
+#define CV_BUILTIN_TYPE_FLOAT128               0x0043
+#define CV_BUILTIN_TYPE_COMPLEX32              0x0050
+#define CV_BUILTIN_TYPE_COMPLEX64              0x0051
+#define CV_BUILTIN_TYPE_COMPLEX80              0x0052
+#define CV_BUILTIN_TYPE_COMPLEX128             0x0053
+#define CV_BUILTIN_TYPE_COMPLEX48              0x0054
+#define CV_BUILTIN_TYPE_COMPLEX16              0x0056
+#define CV_BUILTIN_TYPE_SBYTE                  0x0068
+#define CV_BUILTIN_TYPE_BYTE                   0x0069
+#define CV_BUILTIN_TYPE_NARROW_CHARACTER       0x0070
+#define CV_BUILTIN_TYPE_WIDE_CHARACTER         0x0071
+#define CV_BUILTIN_TYPE_INT16                  0x0072
+#define CV_BUILTIN_TYPE_UINT16                 0x0073
+#define CV_BUILTIN_TYPE_INT32                  0x0074
+#define CV_BUILTIN_TYPE_UINT32                 0x0075
+#define CV_BUILTIN_TYPE_INT64                  0x0076
+#define CV_BUILTIN_TYPE_UINT64                 0x0077
+#define CV_BUILTIN_TYPE_INT128                 0x0078
+#define CV_BUILTIN_TYPE_UINT128                        0x0079
+#define CV_BUILTIN_TYPE_CHARACTER16            0x007a
+#define CV_BUILTIN_TYPE_CHARACTER32            0x007b
+
+// from CV_prmode_e in cvdump
+#define CV_TM_NPTR                     1
+#define CV_TM_NPTR32                   4
+#define CV_TM_NPTR64                   6
+
+struct pdb_type_tree_hasher : nofree_ptr_hash <struct pdb_type>
+{
+  typedef struct pdb_type *value_type;
+  typedef tree compare_type;
+
+  static inline hashval_t hash (compare_type);
+
+  static inline hashval_t hash (const value_type t)
+  {
+    return hash (t->tree);
+  }
+
+  static inline bool equal (const value_type, compare_type);
+};
+
 #endif
-- 
2.26.2

Reply via email to