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