Outputs CodeView S_LDATA32 symbols, for static variables within functions, along with S_BLOCK32 and S_END for the beginning and end of lexical blocks.
gcc/ * dwarf2codeview.cc (enum cv_sym_type): Add S_END and S_BLOCK32. (write_local_s_ldata32): New function. (write_unoptimized_local_variable): New function. (write_s_block32): New function. (write_s_end): New function. (write_unoptimized_function_vars): New function. (write_function): Call write_unoptimized_function_vars. --- gcc/dwarf2codeview.cc | 258 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc index 7e4faaa9388..cb2d64bfcc6 100644 --- a/gcc/dwarf2codeview.cc +++ b/gcc/dwarf2codeview.cc @@ -70,6 +70,8 @@ along with GCC; see the file COPYING3. If not see /* This is enum SYM_ENUM_e in Microsoft's cvinfo.h. */ enum cv_sym_type { + S_END = 0x0006, + S_BLOCK32 = 0x1103, S_LDATA32 = 0x110c, S_GDATA32 = 0x110d, S_COMPILE3 = 0x113c, @@ -986,6 +988,260 @@ end: free (s->data_symbol.name); } +/* Write an S_LDATA32 symbol, representing a static variable within a function. + This symbol can also appear outside of a function block - see + write_data_symbol. */ + +static void +write_local_s_ldata32 (dw_die_ref die, dw_loc_descr_ref loc_ref) +{ + unsigned int label_num = ++sym_label_num; + const char *name = get_AT_string (die, DW_AT_name); + uint32_t type; + + /* This is struct datasym in binutils: + + struct datasym + { + uint16_t size; + uint16_t kind; + uint32_t type; + uint32_t offset; + uint16_t section; + char name[]; + } ATTRIBUTE_PACKED; + */ + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n", + label_num, label_num); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, S_LDATA32); + putc ('\n', asm_out_file); + + type = get_type_num (get_AT_ref (die, DW_AT_type), false, false); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, type); + putc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secrel32 "); + output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr); + fputc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secidx "); + output_addr_const (asm_out_file, loc_ref->dw_loc_oprnd1.v.val_addr); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_ASCII (asm_out_file, name, strlen (name) + 1); + + ASM_OUTPUT_ALIGN (asm_out_file, 2); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); +} + +/* Write a symbol representing an unoptimized variable within a function, if + we're able to translate the DIE's DW_AT_location into its CodeView + equivalent. */ + +static void +write_unoptimized_local_variable (dw_die_ref die) +{ + dw_attr_node *loc; + dw_loc_descr_ref loc_ref; + + loc = get_AT (die, DW_AT_location); + if (!loc) + return; + + if (loc->dw_attr_val.val_class != dw_val_class_loc) + return; + + loc_ref = loc->dw_attr_val.v.val_loc; + if (!loc_ref) + return; + + switch (loc_ref->dw_loc_opc) + { + case DW_OP_addr: + write_local_s_ldata32 (die, loc_ref); + break; + + default: + break; + } +} + +/* Translate a DW_TAG_lexical_block DIE into an S_BLOCK32 symbol, representing + a block within an unoptimized function. Returns false if we're not able + to resolve the location, which will prevent the caller from issuing an + unneeded S_END. */ + +static bool +write_s_block32 (dw_die_ref die) +{ + unsigned int label_num = ++sym_label_num; + dw_attr_node *loc_low, *loc_high; + const char *label_low, *label_high; + rtx rtx_low, rtx_high; + + /* This is struct blocksym in binutils and BLOCKSYM32 in Microsoft's + cvinfo.h: + + struct blocksym + { + uint16_t size; + uint16_t kind; + uint32_t parent; + uint32_t end; + uint32_t len; + uint32_t offset; + uint16_t section; + char name[]; + } ATTRIBUTE_PACKED; + */ + + loc_low = get_AT (die, DW_AT_low_pc); + if (!loc_low) + return false; + + if (loc_low->dw_attr_val.val_class != dw_val_class_lbl_id) + return false; + + label_low = loc_low->dw_attr_val.v.val_lbl_id; + if (!label_low) + return false; + + rtx_low = gen_rtx_SYMBOL_REF (Pmode, label_low); + + loc_high = get_AT (die, DW_AT_high_pc); + if (!loc_high) + return false; + + if (loc_high->dw_attr_val.val_class != dw_val_class_high_pc) + return false; + + label_high = loc_high->dw_attr_val.v.val_lbl_id; + if (!label_high) + return false; + + rtx_high = gen_rtx_SYMBOL_REF (Pmode, label_high); + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n", + label_num, label_num); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, S_BLOCK32); + putc ('\n', asm_out_file); + + /* The parent and end fields get filled in by the linker. */ + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, 0); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + fprint_whex (asm_out_file, 0); + putc ('\n', asm_out_file); + + fputs (integer_asm_op (4, false), asm_out_file); + output_addr_const (asm_out_file, rtx_high); + fputs (" - ", asm_out_file); + output_addr_const (asm_out_file, rtx_low); + putc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secrel32 "); + output_addr_const (asm_out_file, rtx_low); + fputc ('\n', asm_out_file); + + asm_fprintf (asm_out_file, "\t.secidx "); + output_addr_const (asm_out_file, rtx_low); + fputc ('\n', asm_out_file); + + ASM_OUTPUT_ASCII (asm_out_file, "", 1); + + ASM_OUTPUT_ALIGN (asm_out_file, 2); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); + + return true; +} + +/* Write an S_END symbol, which is used to finish off a number of different + symbol types. Here we use it to mark the S_BLOCK32 as finished. */ + +static void +write_s_end (void) +{ + unsigned int label_num = ++sym_label_num; + + fputs (integer_asm_op (2, false), asm_out_file); + asm_fprintf (asm_out_file, + "%L" SYMBOL_END_LABEL "%u - %L" SYMBOL_START_LABEL "%u\n", + label_num, label_num); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_START_LABEL, label_num); + + fputs (integer_asm_op (2, false), asm_out_file); + fprint_whex (asm_out_file, S_END); + putc ('\n', asm_out_file); + + ASM_OUTPUT_ALIGN (asm_out_file, 2); + + targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); +} + +/* Loop through the DIEs in an unoptimized function, writing out any variables + or blocks that we encounter. */ + +static void +write_unoptimized_function_vars (dw_die_ref die) +{ + dw_die_ref first_child, c; + + first_child = dw_get_die_child (die); + + if (!first_child) + return; + + c = first_child; + do + { + c = dw_get_die_sib (c); + + switch (dw_get_die_tag (c)) + { + case DW_TAG_variable: + write_unoptimized_local_variable (c); + break; + + case DW_TAG_lexical_block: + { + bool block_started = write_s_block32 (c); + + write_unoptimized_function_vars (c); + + if (block_started) + write_s_end (); + + break; + } + + default: + break; + } + } + while (c != first_child); +} + /* Write an S_GPROC32_ID symbol, representing a global function, or an S_LPROC32_ID symbol, for a static function. */ @@ -1111,6 +1367,8 @@ write_function (codeview_symbol *s) targetm.asm_out.internal_label (asm_out_file, SYMBOL_END_LABEL, label_num); + write_unoptimized_function_vars (s->function.die); + /* Output the S_PROC_ID_END record. */ label_num = ++sym_label_num; -- 2.44.2