--- gcc/pdbout.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++- gcc/pdbout.h | 10 +++ 2 files changed, 217 insertions(+), 1 deletion(-)
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]; }; -- 2.26.2