Translates DW_TAG_pointer_type DIEs into LF_POINTER symbols, which get output into the .debug$T section.
gcc/ * dwarf2codeview.cc (FIRST_TYPE): Define. (struct codeview_custom_type): New structure. (custom_types, last_custom_type): New variables. (get_type_num): Prototype. (write_lf_pointer, write_custom_types): New functions. (codeview_debug_finish): Call write_custom_types. (add_custom_type, get_type_num_pointer_type): New functions. (get_type_num): Handle DW_TAG_pointer_type DIEs. * dwarf2codeview.h (T_VOID): Define. (CV_POINTER_32, CV_POINTER_64): Likewise. (T_32PVOID, T_64PVOID): Likewise. (CV_PTR_NEAR32, CV_PTR64, LF_POINTER): Likewise. --- gcc/dwarf2codeview.cc | 179 +++++++++++++++++++++++++++++++++++++++++- gcc/dwarf2codeview.h | 13 +++ 2 files changed, 188 insertions(+), 4 deletions(-) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index 5006a176260..51401f2d5bc 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -56,6 +56,8 @@ along with GCC; see the file COPYING3. If not see #define CV_CFL_C 0x00 #define CV_CFL_CXX 0x01 +#define FIRST_TYPE 0x1000 + #define LINE_LABEL "Lcvline" #define END_FUNC_LABEL "Lcvendfunc" #define SYMBOL_START_LABEL "Lcvsymstart" @@ -168,6 +170,22 @@ struct die_hasher : free_ptr_hash <codeview_type> } }; +struct codeview_custom_type +{ + struct codeview_custom_type *next; + uint32_t num; + uint16_t kind; + + union + { + struct + { + uint32_t base_type; + uint32_t attributes; + } lf_pointer; + }; +}; + static unsigned int line_label_num; static unsigned int func_label_num; static unsigned int sym_label_num; @@ -181,6 +199,9 @@ static const char* last_filename; static uint32_t last_file_id; static codeview_symbol *sym, *last_sym; static hash_table<die_hasher> *types_htab; +static codeview_custom_type *custom_types, *last_custom_type; + +static uint32_t get_type_num (dw_die_ref type); /* Record new line number against the current function. */ @@ -845,6 +866,71 @@ write_codeview_symbols (void) asm_fprintf (asm_out_file, "%LLcv_syms_end:\n"); } +/* Write an LF_POINTER type. */ + +static void +write_lf_pointer (codeview_custom_type *t) +{ + /* This is lf_pointer in binutils and lfPointer in Microsoft's cvinfo.h: + + struct lf_pointer + { + uint16_t size; + uint16_t kind; + uint32_t base_type; + uint32_t attributes; + } ATTRIBUTE_PACKED; + */ + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, "%LLcv_type%x_end - %LLcv_type%x_start\n", + t->num, t->num); + + asm_fprintf (asm_out_file, "%LLcv_type%x_start:\n", t->num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, t->kind); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, t->lf_pointer.base_type); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, t->lf_pointer.attributes); + putc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "%LLcv_type%x_end:\n", t->num); +} + +/* Write the .debug$T section, which contains all of our custom type + definitions. */ + +static void +write_custom_types (void) +{ + targetm.asm_out.named_section (".debug$T", SECTION_DEBUG, NULL); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, CV_SIGNATURE_C13); + putc ('\n', asm_out_file); + + while (custom_types) + { + codeview_custom_type *n = custom_types->next; + + switch (custom_types->kind) + { + case LF_POINTER: + write_lf_pointer (custom_types); + break; + } + + free (custom_types); + custom_types = n; + } +} + /* Finish CodeView debug info emission. */ void @@ -861,6 +947,9 @@ codeview_debug_finish (void) write_line_numbers (); write_codeview_symbols (); + if (custom_types) + write_custom_types (); + if (types_htab) delete types_htab; } @@ -993,10 +1082,88 @@ get_type_num_base_type (dw_die_ref type) } } -/* Process a DIE representing a type definition and return its number. If - it's something we can't handle, return 0. We keep a hash table so that - we're not adding the same type multiple times - though if we do it's not - disastrous, as ld will deduplicate everything for us. */ +/* Add a new codeview_custom_type to our singly-linked custom_types list. */ + +static void +add_custom_type (codeview_custom_type *ct) +{ + uint32_t num; + + if (last_custom_type) + { + num = last_custom_type->num + 1; + last_custom_type->next = ct; + } + else + { + num = FIRST_TYPE; + custom_types = ct; + } + + last_custom_type = ct; + + ct->num = num; +} + +/* Process a DW_TAG_pointer_type DIE. If this is a pointer to a builtin + type, return the predefined constant for this. Otherwise, add a new + LF_POINTER type and return its number. */ + +static uint32_t +get_type_num_pointer_type (dw_die_ref type) +{ + uint32_t base_type_num, byte_size; + dw_die_ref base_type; + codeview_custom_type *ct; + + byte_size = get_AT_unsigned (type, DW_AT_byte_size); + if (byte_size != 4 && byte_size != 8) + return 0; + + base_type = get_AT_ref (type, DW_AT_type); + + /* If DW_AT_type is not set, this must be a void pointer. */ + if (!base_type) + return byte_size == 4 ? T_32PVOID : T_64PVOID; + + base_type_num = get_type_num (base_type); + if (base_type_num == 0) + return 0; + + /* Pointers to builtin types have predefined type numbers, with the top byte + determining the pointer size - 0x0400 for a 32-bit pointer and 0x0600 + for 64-bit. */ + if (base_type_num < FIRST_TYPE && !(base_type_num & 0xff00)) + { + if (byte_size == 4) + return CV_POINTER_32 | base_type_num; + else + return CV_POINTER_64 | base_type_num; + } + + ct = (codeview_custom_type *) xmalloc (sizeof (codeview_custom_type)); + + ct->next = NULL; + ct->kind = LF_POINTER; + ct->lf_pointer.base_type = base_type_num; + + if (byte_size == 4) + ct->lf_pointer.attributes = CV_PTR_NEAR32; + else + ct->lf_pointer.attributes = CV_PTR_64; + + ct->lf_pointer.attributes |= byte_size << 13; + + add_custom_type (ct); + + return ct->num; +} + +/* Process a DIE representing a type definition, add a CodeView type if + necessary, and return its number. If it's something we can't handle, return + 0. We keep a hash table so that we're not adding the same type multiple + times - though if we do it's not disastrous, as ld will deduplicate + everything for us. */ static uint32_t get_type_num (dw_die_ref type) @@ -1030,6 +1197,10 @@ get_type_num (dw_die_ref type) t->num = get_type_num (get_AT_ref (type, DW_AT_type)); break; + case DW_TAG_pointer_type: + t->num = get_type_num_pointer_type (type); + break; + default: t->num = 0; break; diff --git a/gcc/dwarf2codeview.h b/gcc/dwarf2codeview.h index 7d8a4c161f4..0af4c98250f 100644 --- a/gcc/dwarf2codeview.h +++ b/gcc/dwarf2codeview.h @@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see /* Constants for in-built types. */ +#define T_VOID 0x0003 #define T_CHAR 0x0010 #define T_SHORT 0x0011 #define T_LONG 0x0012 @@ -46,6 +47,18 @@ along with GCC; see the file COPYING3. If not see #define T_CHAR32 0x007b #define T_CHAR8 0x007c +#define CV_POINTER_32 0x0400 +#define CV_POINTER_64 0x0600 +#define T_32PVOID (T_VOID | CV_POINTER_32) +#define T_64PVOID (T_VOID | CV_POINTER_64) + +/* LF_POINTER attributes. */ +#define CV_PTR_NEAR32 0x0a +#define CV_PTR_64 0x0c + +/* Constants for type definitions. */ +#define LF_POINTER 0x1002 + /* Debug Format Interface. Used in dwarf2out.cc. */ extern void codeview_debug_finish (void); -- 2.44.2