--- gcc/pdbout.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++--- gcc/pdbout.h | 36 ++++++++++++++ 2 files changed, 161 insertions(+), 6 deletions(-)
diff --git a/gcc/pdbout.c b/gcc/pdbout.c index 64f7c1d71bc..08bb14364e5 100644 --- a/gcc/pdbout.c +++ b/gcc/pdbout.c @@ -76,6 +76,7 @@ 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 *arglist_types = NULL; +static struct pdb_type *pointer_types = NULL; static struct pdb_type *proc_types = NULL; static struct pdb_source_file *source_files = NULL, *last_source_file = NULL; static uint32_t source_file_string_offset = 1; @@ -803,6 +804,17 @@ free_type (struct pdb_type *t) free (t); } +/* Output a lfPointer structure. */ +static void +write_pointer (struct pdb_pointer *ptr) +{ + fprintf (asm_out_file, "\t.short\t0xa\n"); + fprintf (asm_out_file, "\t.short\t0x%x\n", LF_POINTER); + fprintf (asm_out_file, "\t.short\t0x%x\n", ptr->type ? ptr->type->id : 0); + fprintf (asm_out_file, "\t.short\t0\n"); // padding + fprintf (asm_out_file, "\t.long\t0x%x\n", ptr->attr.num); +} + /* Output a lfArgList structure, describing the arguments that a * procedure expects. */ static void @@ -857,6 +869,13 @@ write_type (struct pdb_type *t) { switch (t->cv_type) { + case LF_POINTER: + if (t->id < FIRST_TYPE_NUM) // pointer to builtin + return; + + write_pointer ((struct pdb_pointer *) t->data); + break; + case LF_ARGLIST: write_arglist ((struct pdb_arglist *) t->data); break; @@ -910,13 +929,38 @@ number_types (void) continue; } - t->id = type_num; - type_num++; - - if (type_num == 0) // overflow + switch (t->cv_type) { - fprintf (stderr, "too many CodeView types\n"); - xexit (1); + case LF_POINTER: + { + struct pdb_pointer *ptr = (struct pdb_pointer *) t->data; + + // pointers to builtins have their own constants + if (ptr->type && ptr->type->id != 0 && ptr->type->id < 0x100) + { + if (ptr->attr.s.ptrtype == CV_PTR_NEAR32) + { + t->id = (CV_TM_NPTR32 << 8) | ptr->type->id; + break; + } + else if (ptr->attr.s.ptrtype == CV_PTR_64) + { + t->id = (CV_TM_NPTR64 << 8) | ptr->type->id; + break; + } + } + [[fallthrough]]; + } + + default: + t->id = type_num; + type_num++; + + if (type_num == 0) // overflow + { + fprintf (stderr, "too many CodeView types\n"); + xexit (1); + } } t = t->next; @@ -1072,6 +1116,77 @@ add_arglist_type (struct pdb_type *t) return t; } +/* Given a pointer type t, allocate a new pdb_type and add it to the + * type list. */ +static struct pdb_type * +find_type_pointer (tree t) +{ + struct pdb_type *ptrtype, *t2, *last_entry = NULL, *type; + struct pdb_pointer *ptr, v; + unsigned int size = TREE_INT_CST_ELT (TYPE_SIZE (t), 0) / 8; + struct pdb_type **slot; + + type = find_type (TREE_TYPE (t)); + + if (!type) + return NULL; + + v.attr.num = 0; + + v.attr.s.size = size; + + if (size == 8) + v.attr.s.ptrtype = CV_PTR_64; + else if (size == 4) + v.attr.s.ptrtype = CV_PTR_NEAR32; + + if (TREE_CODE (t) == REFERENCE_TYPE) + v.attr.s.ptrmode = + TYPE_REF_IS_RVALUE (t) ? CV_PTR_MODE_RVREF : CV_PTR_MODE_LVREF; + + t2 = pointer_types; + while (t2) + { + ptr = (struct pdb_pointer *) t2->data; + + if (ptr->type == type && ptr->attr.num == v.attr.num) + return t2; + + last_entry = t2; + t2 = t2->next2; + } + + ptrtype = + (struct pdb_type *) xmalloc (offsetof (struct pdb_type, data) + + sizeof (struct pdb_pointer)); + ptrtype->cv_type = LF_POINTER; + ptrtype->tree = t; + ptrtype->next = ptrtype->next2 = NULL; + ptrtype->id = 0; + + ptr = (struct pdb_pointer *) ptrtype->data; + ptr->type = type; + ptr->attr.num = v.attr.num; + + if (last_entry) + last_entry->next2 = ptrtype; + else + pointer_types = ptrtype; + + if (last_type) + last_type->next = ptrtype; + else + types = ptrtype; + + last_type = ptrtype; + + slot = + tree_hash_table.find_slot_with_hash (t, htab_hash_pointer (t), INSERT); + *slot = ptrtype; + + return ptrtype; +} + /* Given a function type t, allocate a new pdb_type and add it to the * type list. */ static struct pdb_type * @@ -1478,6 +1593,10 @@ find_type (tree t) switch (TREE_CODE (t)) { + case POINTER_TYPE: + case REFERENCE_TYPE: + return find_type_pointer (t); + case FUNCTION_TYPE: case METHOD_TYPE: return find_type_function (t); diff --git a/gcc/pdbout.h b/gcc/pdbout.h index b9e56a66069..a660728158e 100644 --- a/gcc/pdbout.h +++ b/gcc/pdbout.h @@ -21,6 +21,7 @@ #define GCC_PDBOUT_H 1 #define S_END 0x0006 +#define LF_POINTER 0x1002 #define LF_PROCEDURE 0x1008 #define S_BLOCK32 0x1103 #define S_REGISTER 0x1106 @@ -124,6 +125,41 @@ struct pdb_global_var struct pdb_type *type; }; +// from CV_ptrtype_e in cvdump +#define CV_PTR_NEAR32 0x0a +#define CV_PTR_64 0x0c + +// from CV_ptrmode_e in cvdump +#define CV_PTR_MODE_PTR 0x0 +#define CV_PTR_MODE_LVREF 0x1 +#define CV_PTR_MODE_PMEM 0x2 +#define CV_PTR_MODE_PMFUNC 0x3 +#define CV_PTR_MODE_RVREF 0x4 + +struct pdb_pointer +{ + struct pdb_type *type; + union + { + struct + { + uint32_t ptrtype:5; + uint32_t ptrmode:3; + uint32_t isflat32:1; + uint32_t isvolatile:1; + uint32_t isconst:1; + uint32_t isunaligned:1; + uint32_t isrestrict:1; + uint32_t size:6; + uint32_t ismocom:1; + uint32_t islref:1; + uint32_t isrref:1; + uint32_t unused:10; + } s; + uint32_t num; + } attr; +}; + struct pdb_arglist { unsigned int count; -- 2.26.2