---
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