X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fdwarf2out.c;h=700f7c64bd3a4b38b5fcbe12503219a2910c7849;hp=32bb4dc929aab2671874488e069f690a53df74e4;hb=a464988454e792146712dbdfd91047c94dcc5cca;hpb=d7175aeff80486d3421f38002845779158ce107b diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 32bb4dc929a..700f7c64bd3 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1,6 +1,6 @@ /* Output Dwarf2 format symbol table information from GCC. Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Gary Funck (gary@intrepid.com). Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com). @@ -92,6 +92,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "tree-pass.h" #include "tree-flow.h" +#include "cfglayout.h" static void dwarf2out_source_line (unsigned int, const char *, int, bool); static rtx last_var_location_insn; @@ -153,7 +154,7 @@ dwarf2out_do_frame (void) return true; if ((flag_unwind_tables || flag_exceptions) - && targetm.except_unwind_info () == UI_DWARF2) + && targetm.except_unwind_info (&global_options) == UI_DWARF2) return true; return false; @@ -189,7 +190,7 @@ dwarf2out_do_cfi_asm (void) dwarf2 unwind info for exceptions, then emit .debug_frame by hand. */ if (!HAVE_GAS_CFI_SECTIONS_DIRECTIVE && !flag_unwind_tables && !flag_exceptions - && targetm.except_unwind_info () != UI_DWARF2) + && targetm.except_unwind_info (&global_options) != UI_DWARF2) return false; saved_do_cfi_asm = true; @@ -227,8 +228,6 @@ static GTY(()) section *debug_line_section; static GTY(()) section *debug_loc_section; static GTY(()) section *debug_pubnames_section; static GTY(()) section *debug_pubtypes_section; -static GTY(()) section *debug_dcall_section; -static GTY(()) section *debug_vcall_section; static GTY(()) section *debug_str_section; static GTY(()) section *debug_ranges_section; static GTY(()) section *debug_frame_section; @@ -282,7 +281,7 @@ dw_cfi_node; It can now be either REG + CFA_OFFSET or *(REG + BASE_OFFSET) + CFA_OFFSET. Instead of passing around REG and OFFSET, we pass a copy of this structure. */ -typedef struct GTY(()) cfa_loc { +typedef struct cfa_loc { HOST_WIDE_INT offset; HOST_WIDE_INT base_offset; unsigned int reg; @@ -303,10 +302,8 @@ typedef struct GTY(()) dw_fde_struct { const char *dw_fde_end; const char *dw_fde_vms_end_prologue; const char *dw_fde_vms_begin_epilogue; - const char *dw_fde_hot_section_label; - const char *dw_fde_hot_section_end_label; - const char *dw_fde_unlikely_section_label; - const char *dw_fde_unlikely_section_end_label; + const char *dw_fde_second_begin; + const char *dw_fde_second_end; dw_cfi_ref dw_fde_cfi; dw_cfi_ref dw_fde_switch_cfi; /* Last CFI before switching sections. */ HOST_WIDE_INT stack_realignment; @@ -325,13 +322,9 @@ typedef struct GTY(()) dw_fde_struct { unsigned drap_reg_saved: 1; /* True iff dw_fde_begin label is in text_section or cold_text_section. */ unsigned in_std_section : 1; - /* True iff dw_fde_unlikely_section_label is in text_section or + /* True iff dw_fde_second_begin label is in text_section or cold_text_section. */ - unsigned cold_in_std_section : 1; - /* True iff switched sections. */ - unsigned dw_fde_switched_sections : 1; - /* True iff switching from cold to hot section. */ - unsigned dw_fde_switched_cold_to_hot : 1; + unsigned second_in_std_section : 1; } dw_fde_node; @@ -474,7 +467,7 @@ static bool clobbers_queued_reg_save (const_rtx); static void dwarf2out_frame_debug_expr (rtx, const char *); /* Support for complex CFA locations. */ -static void output_cfa_loc (dw_cfi_ref); +static void output_cfa_loc (dw_cfi_ref, int); static void output_cfa_loc_raw (dw_cfi_ref); static void get_cfa_from_loc_descr (dw_cfa_location *, struct dw_loc_descr_struct *); @@ -619,7 +612,7 @@ should_emit_struct_debug (tree type, enum debug_info_usage usage) if (criterion == DINFO_STRUCT_FILE_ANY) return DUMP_GSTRUCT (type, usage, criterion, generic, false, true); - type_decl = TYPE_STUB_DECL (type); + type_decl = TYPE_STUB_DECL (TYPE_MAIN_VARIANT (type)); if (criterion == DINFO_STRUCT_FILE_SYS && DECL_IN_SYSTEM_HEADER (type_decl)) return DUMP_GSTRUCT (type, usage, criterion, generic, false, true); @@ -2240,7 +2233,7 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label) cfa.base_offset = -cfa_store.offset Rule 11: - (set (mem ({pre_inc,pre_dec} sp:cfa_store.reg)) ) + (set (mem ({pre_inc,pre_dec,post_dec} sp:cfa_store.reg)) ) effects: cfa_store.offset += -/+ mode_size(mem) cfa.offset = cfa_store.offset if cfa.reg == sp cfa.reg = sp @@ -2259,7 +2252,7 @@ dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label) cfa.base_offset = -{cfa_store,cfa_temp}.offset Rule 14: - (set (mem (postinc :cfa_temp )) ) + (set (mem (post_inc :cfa_temp )) ) effects: cfa.reg = cfa.base_offset = -cfa_temp.offset cfa_temp.offset -= mode_size(mem) @@ -2592,6 +2585,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) /* Rule 11 */ case PRE_INC: case PRE_DEC: + case POST_DEC: offset = GET_MODE_SIZE (GET_MODE (dest)); if (GET_CODE (XEXP (dest, 0)) == PRE_INC) offset = -offset; @@ -2616,7 +2610,10 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) if (cfa.reg == STACK_POINTER_REGNUM) cfa.offset = cfa_store.offset; - offset = -cfa_store.offset; + if (GET_CODE (XEXP (dest, 0)) == POST_DEC) + offset += -cfa_store.offset; + else + offset = -cfa_store.offset; break; /* Rule 12 */ @@ -2791,38 +2788,6 @@ dwarf2out_frame_debug (rtx insn, bool after_p) rtx note, n; bool handled_one = false; - if (insn == NULL_RTX) - { - size_t i; - - /* Flush any queued register saves. */ - dwarf2out_flush_queued_reg_saves (); - - /* Set up state for generating call frame debug info. */ - lookup_cfa (&cfa); - gcc_assert (cfa.reg - == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)); - - cfa.reg = STACK_POINTER_REGNUM; - cfa_store = cfa; - cfa_temp.reg = -1; - cfa_temp.offset = 0; - - for (i = 0; i < num_regs_saved_in_regs; i++) - { - regs_saved_in_regs[i].orig_reg = NULL_RTX; - regs_saved_in_regs[i].saved_in_reg = NULL_RTX; - } - num_regs_saved_in_regs = 0; - - if (barrier_args_size) - { - XDELETEVEC (barrier_args_size); - barrier_args_size = NULL; - } - return; - } - if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn)) dwarf2out_flush_queued_reg_saves (); @@ -2940,6 +2905,40 @@ dwarf2out_frame_debug (rtx insn, bool after_p) dwarf2out_flush_queued_reg_saves (); } +/* Called once at the start of final to initialize some data for the + current function. */ +void +dwarf2out_frame_debug_init (void) +{ + size_t i; + + /* Flush any queued register saves. */ + dwarf2out_flush_queued_reg_saves (); + + /* Set up state for generating call frame debug info. */ + lookup_cfa (&cfa); + gcc_assert (cfa.reg + == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM)); + + cfa.reg = STACK_POINTER_REGNUM; + cfa_store = cfa; + cfa_temp.reg = -1; + cfa_temp.offset = 0; + + for (i = 0; i < num_regs_saved_in_regs; i++) + { + regs_saved_in_regs[i].orig_reg = NULL_RTX; + regs_saved_in_regs[i].saved_in_reg = NULL_RTX; + } + num_regs_saved_in_regs = 0; + + if (barrier_args_size) + { + XDELETEVEC (barrier_args_size); + barrier_args_size = NULL; + } +} + /* Determine if we need to save and restore CFI information around this epilogue. If SIBCALL is true, then this is a sibcall epilogue. If we do need to save/restore, then emit the save now, and insert a @@ -3317,7 +3316,7 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh) case DW_CFA_def_cfa_expression: case DW_CFA_expression: - output_cfa_loc (cfi); + output_cfa_loc (cfi, for_eh); break; case DW_CFA_GNU_negative_offset_extended: @@ -3625,28 +3624,8 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, dw2_asm_output_offset (DWARF_OFFSET_SIZE, section_start_label, debug_frame_section, "FDE CIE offset"); - if (!fde->dw_fde_switched_sections) - { - begin = fde->dw_fde_begin; - end = fde->dw_fde_end; - } - else - { - /* For the first section, prefer dw_fde_begin over - dw_fde_{hot,cold}_section_label, as the latter - might be separated from the real start of the - function by alignment padding. */ - if (!second) - begin = fde->dw_fde_begin; - else if (fde->dw_fde_switched_cold_to_hot) - begin = fde->dw_fde_hot_section_label; - else - begin = fde->dw_fde_unlikely_section_label; - if (second ^ fde->dw_fde_switched_cold_to_hot) - end = fde->dw_fde_unlikely_section_end_label; - else - end = fde->dw_fde_hot_section_end_label; - } + begin = second ? fde->dw_fde_second_begin : fde->dw_fde_begin; + end = second ? fde->dw_fde_second_end : fde->dw_fde_end; if (for_eh) { @@ -3707,7 +3686,7 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second, /* Loop through the Call Frame Instructions associated with this FDE. */ fde->dw_fde_current_label = begin; - if (!fde->dw_fde_switched_sections) + if (fde->dw_fde_second_begin == NULL) for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next) output_cfi (cfi, fde, for_eh); else if (!second) @@ -3986,7 +3965,7 @@ output_call_frame_info (int for_eh) if (for_eh && !fde_needed_for_eh_p (fde)) continue; - for (k = 0; k < (fde->dw_fde_switched_sections ? 2 : 1); k++) + for (k = 0; k < (fde->dw_fde_second_begin ? 2 : 1); k++) output_fde (fde, for_eh, k, section_start_label, fde_encoding, augmentation, any_lsda_needed, lsda_encoding); } @@ -4072,7 +4051,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, call-site information. We must emit this label if it might be used. */ if (!do_frame && (!flag_exceptions - || targetm.except_unwind_info () != UI_TARGET)) + || targetm.except_unwind_info (&global_options) != UI_TARGET)) return; fnsec = function_section (current_function_decl); @@ -4104,14 +4083,10 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, fde = &fde_table[fde_table_in_use++]; fde->decl = current_function_decl; fde->dw_fde_begin = dup_label; - fde->dw_fde_current_label = dup_label; - fde->dw_fde_hot_section_label = NULL; - fde->dw_fde_hot_section_end_label = NULL; - fde->dw_fde_unlikely_section_label = NULL; - fde->dw_fde_unlikely_section_end_label = NULL; - fde->dw_fde_switched_sections = 0; - fde->dw_fde_switched_cold_to_hot = 0; fde->dw_fde_end = NULL; + fde->dw_fde_current_label = dup_label; + fde->dw_fde_second_begin = NULL; + fde->dw_fde_second_end = NULL; fde->dw_fde_vms_end_prologue = NULL; fde->dw_fde_vms_begin_epilogue = NULL; fde->dw_fde_cfi = NULL; @@ -4122,27 +4097,9 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, fde->nothrow = crtl->nothrow; fde->drap_reg = INVALID_REGNUM; fde->vdrap_reg = INVALID_REGNUM; - if (flag_reorder_blocks_and_partition) - { - section *unlikelysec; - if (first_function_block_is_cold) - fde->in_std_section = 1; - else - fde->in_std_section - = (fnsec == text_section - || (cold_text_section && fnsec == cold_text_section)); - unlikelysec = unlikely_text_section (); - fde->cold_in_std_section - = (unlikelysec == text_section - || (cold_text_section && unlikelysec == cold_text_section)); - } - else - { - fde->in_std_section - = (fnsec == text_section - || (cold_text_section && fnsec == cold_text_section)); - fde->cold_in_std_section = 0; - } + fde->in_std_section = (fnsec == text_section + || (cold_text_section && fnsec == cold_text_section)); + fde->second_in_std_section = 0; args_size = old_args_size = 0; @@ -4238,7 +4195,8 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED, ASM_OUTPUT_LABEL (asm_out_file, label); fde = current_fde (); gcc_assert (fde != NULL); - fde->dw_fde_end = xstrdup (label); + if (fde->dw_fde_second_begin == NULL) + fde->dw_fde_end = xstrdup (label); } void @@ -4256,7 +4214,7 @@ dwarf2out_frame_init (void) dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET); if (targetm.debug_unwind_info () == UI_DWARF2 - || targetm.except_unwind_info () == UI_DWARF2) + || targetm.except_unwind_info (&global_options) == UI_DWARF2) initial_return_save (INCOMING_RETURN_ADDR_RTX); } @@ -4269,7 +4227,7 @@ dwarf2out_frame_finish (void) /* Output another copy for the unwinder. */ if ((flag_unwind_tables || flag_exceptions) - && targetm.except_unwind_info () == UI_DWARF2) + && targetm.except_unwind_info (&global_options) == UI_DWARF2) output_call_frame_info (1); } @@ -4285,20 +4243,30 @@ dwarf2out_note_section_used (void) cold_text_section_used = true; } +static void var_location_switch_text_section (void); +static void set_cur_line_info_table (section *); + void dwarf2out_switch_text_section (void) { + section *sect; dw_fde_ref fde = current_fde (); + dw_cfi_ref cfi; - gcc_assert (cfun && fde && !fde->dw_fde_switched_sections); - - fde->dw_fde_switched_sections = 1; - fde->dw_fde_switched_cold_to_hot = !in_cold_section_p; + gcc_assert (cfun && fde && fde->dw_fde_second_begin == NULL); - fde->dw_fde_hot_section_label = crtl->subsections.hot_section_label; - fde->dw_fde_hot_section_end_label = crtl->subsections.hot_section_end_label; - fde->dw_fde_unlikely_section_label = crtl->subsections.cold_section_label; - fde->dw_fde_unlikely_section_end_label = crtl->subsections.cold_section_end_label; + if (!in_cold_section_p) + { + fde->dw_fde_end = crtl->subsections.cold_section_end_label; + fde->dw_fde_second_begin = crtl->subsections.hot_section_label; + fde->dw_fde_second_end = crtl->subsections.hot_section_end_label; + } + else + { + fde->dw_fde_end = crtl->subsections.hot_section_end_label; + fde->dw_fde_second_begin = crtl->subsections.cold_section_label; + fde->dw_fde_second_end = crtl->subsections.cold_section_end_label; + } have_multiple_function_sections = true; /* Reset the current label on switching text sections, so that we @@ -4313,7 +4281,12 @@ dwarf2out_switch_text_section (void) fprintf (asm_out_file, "\t.cfi_endproc\n"); /* Now do the real section switch. */ - switch_to_section (current_function_section ()); + sect = current_function_section (); + switch_to_section (sect); + + fde->second_in_std_section + = (sect == text_section + || (cold_text_section && sect == cold_text_section)); if (dwarf2out_do_cfi_asm ()) { @@ -4322,16 +4295,14 @@ dwarf2out_switch_text_section (void) again. */ output_cfis (fde->dw_fde_cfi, true, fde, true); } - else - { - dw_cfi_ref cfi = fde->dw_fde_cfi; + cfi = fde->dw_fde_cfi; + if (cfi) + while (cfi->dw_cfi_next != NULL) + cfi = cfi->dw_cfi_next; + fde->dw_fde_switch_cfi = cfi; + var_location_switch_text_section (); - cfi = fde->dw_fde_cfi; - if (cfi) - while (cfi->dw_cfi_next != NULL) - cfi = cfi->dw_cfi_next; - fde->dw_fde_switch_cfi = cfi; - } + set_cur_line_info_table (sect); } /* And now, the subset of the debugging information support code necessary @@ -4464,6 +4435,11 @@ typedef struct GTY(()) dw_loc_list_struct { const char *section; /* Section this loclist is relative to */ dw_loc_descr_ref expr; hashval_t hash; + /* True if all addresses in this and subsequent lists are known to be + resolved. */ + bool resolved_addr; + /* True if this list has been replaced by dw_loc_next. */ + bool replaced; bool emitted; } dw_loc_list_node; @@ -4794,6 +4770,8 @@ dwarf_stack_op_name (unsigned int op) return "DW_OP_GNU_encoded_addr"; case DW_OP_GNU_implicit_pointer: return "DW_OP_GNU_implicit_pointer"; + case DW_OP_GNU_entry_value: + return "DW_OP_GNU_entry_value"; default: return "OP_"; @@ -4900,6 +4878,8 @@ loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset) #define DWARF_REF_SIZE \ (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE) +static unsigned long size_of_locs (dw_loc_descr_ref); + /* Return the size of a location descriptor. */ static unsigned long @@ -5015,6 +4995,12 @@ size_of_loc_descr (dw_loc_descr_ref loc) case DW_OP_GNU_implicit_pointer: size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int); break; + case DW_OP_GNU_entry_value: + { + unsigned long op_size = size_of_locs (loc->dw_loc_oprnd1.v.val_loc); + size += size_of_uleb128 (op_size) + op_size; + break; + } default: break; } @@ -5052,11 +5038,17 @@ size_of_locs (dw_loc_descr_ref loc) static HOST_WIDE_INT extract_int (const unsigned char *, unsigned); static void get_ref_die_offset_label (char *, dw_die_ref); +static void output_loc_sequence (dw_loc_descr_ref, int); -/* Output location description stack opcode's operands (if any). */ +/* Output location description stack opcode's operands (if any). + The for_eh_or_skip parameter controls whether register numbers are + converted using DWARF2_FRAME_REG_OUT, which is needed in the case that + hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind + info). This should be suppressed for the cases that have not been converted + (i.e. symbolic debug info), by setting the parameter < 0. See PR47324. */ static void -output_loc_operands (dw_loc_descr_ref loc) +output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip) { dw_val_ref val1 = &loc->dw_loc_oprnd1; dw_val_ref val2 = &loc->dw_loc_oprnd2; @@ -5227,14 +5219,28 @@ output_loc_operands (dw_loc_descr_ref loc) dw2_asm_output_data_sleb128 (val1->v.val_int, NULL); break; case DW_OP_regx: - dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL); + { + unsigned r = val1->v.val_unsigned; + if (for_eh_or_skip >= 0) + r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip); + gcc_assert (size_of_uleb128 (r) + == size_of_uleb128 (val1->v.val_unsigned)); + dw2_asm_output_data_uleb128 (r, NULL); + } break; case DW_OP_fbreg: dw2_asm_output_data_sleb128 (val1->v.val_int, NULL); break; case DW_OP_bregx: - dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL); - dw2_asm_output_data_sleb128 (val2->v.val_int, NULL); + { + unsigned r = val1->v.val_unsigned; + if (for_eh_or_skip >= 0) + r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip); + gcc_assert (size_of_uleb128 (r) + == size_of_uleb128 (val1->v.val_unsigned)); + dw2_asm_output_data_uleb128 (r, NULL); + dw2_asm_output_data_sleb128 (val2->v.val_int, NULL); + } break; case DW_OP_piece: dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL); @@ -5282,25 +5288,53 @@ output_loc_operands (dw_loc_descr_ref loc) } break; + case DW_OP_GNU_entry_value: + dw2_asm_output_data_uleb128 (size_of_locs (val1->v.val_loc), NULL); + output_loc_sequence (val1->v.val_loc, for_eh_or_skip); + break; + default: /* Other codes have no operands. */ break; } } -/* Output a sequence of location operations. */ +/* Output a sequence of location operations. + The for_eh_or_skip parameter controls whether register numbers are + converted using DWARF2_FRAME_REG_OUT, which is needed in the case that + hard reg numbers have been processed via DWARF_FRAME_REGNUM (i.e. for unwind + info). This should be suppressed for the cases that have not been converted + (i.e. symbolic debug info), by setting the parameter < 0. See PR47324. */ static void -output_loc_sequence (dw_loc_descr_ref loc) +output_loc_sequence (dw_loc_descr_ref loc, int for_eh_or_skip) { for (; loc != NULL; loc = loc->dw_loc_next) { + enum dwarf_location_atom opc = loc->dw_loc_opc; /* Output the opcode. */ - dw2_asm_output_data (1, loc->dw_loc_opc, - "%s", dwarf_stack_op_name (loc->dw_loc_opc)); + if (for_eh_or_skip >= 0 + && opc >= DW_OP_breg0 && opc <= DW_OP_breg31) + { + unsigned r = (opc - DW_OP_breg0); + r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip); + gcc_assert (r <= 31); + opc = (enum dwarf_location_atom) (DW_OP_breg0 + r); + } + else if (for_eh_or_skip >= 0 + && opc >= DW_OP_reg0 && opc <= DW_OP_reg31) + { + unsigned r = (opc - DW_OP_reg0); + r = DWARF2_FRAME_REG_OUT (r, for_eh_or_skip); + gcc_assert (r <= 31); + opc = (enum dwarf_location_atom) (DW_OP_reg0 + r); + } + + dw2_asm_output_data (1, opc, + "%s", dwarf_stack_op_name (opc)); /* Output the operand(s) (if any). */ - output_loc_operands (loc); + output_loc_operands (loc, for_eh_or_skip); } } @@ -5361,9 +5395,18 @@ output_loc_operands_raw (dw_loc_descr_ref loc) } break; + case DW_OP_regx: + { + unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1); + gcc_assert (size_of_uleb128 (r) + == size_of_uleb128 (val1->v.val_unsigned)); + fputc (',', asm_out_file); + dw2_asm_output_data_uleb128_raw (r); + } + break; + case DW_OP_constu: case DW_OP_plus_uconst: - case DW_OP_regx: case DW_OP_piece: fputc (',', asm_out_file); dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned); @@ -5414,13 +5457,19 @@ output_loc_operands_raw (dw_loc_descr_ref loc) break; case DW_OP_bregx: - fputc (',', asm_out_file); - dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned); - fputc (',', asm_out_file); - dw2_asm_output_data_sleb128_raw (val2->v.val_int); + { + unsigned r = DWARF2_FRAME_REG_OUT (val1->v.val_unsigned, 1); + gcc_assert (size_of_uleb128 (r) + == size_of_uleb128 (val1->v.val_unsigned)); + fputc (',', asm_out_file); + dw2_asm_output_data_uleb128_raw (r); + fputc (',', asm_out_file); + dw2_asm_output_data_sleb128_raw (val2->v.val_int); + } break; case DW_OP_GNU_implicit_pointer: + case DW_OP_GNU_entry_value: gcc_unreachable (); break; @@ -5435,8 +5484,24 @@ output_loc_sequence_raw (dw_loc_descr_ref loc) { while (1) { + enum dwarf_location_atom opc = loc->dw_loc_opc; + /* Output the opcode. */ + if (opc >= DW_OP_breg0 && opc <= DW_OP_breg31) + { + unsigned r = (opc - DW_OP_breg0); + r = DWARF2_FRAME_REG_OUT (r, 1); + gcc_assert (r <= 31); + opc = (enum dwarf_location_atom) (DW_OP_breg0 + r); + } + else if (opc >= DW_OP_reg0 && opc <= DW_OP_reg31) + { + unsigned r = (opc - DW_OP_reg0); + r = DWARF2_FRAME_REG_OUT (r, 1); + gcc_assert (r <= 31); + opc = (enum dwarf_location_atom) (DW_OP_reg0 + r); + } /* Output the opcode. */ - fprintf (asm_out_file, "%#x", loc->dw_loc_opc); + fprintf (asm_out_file, "%#x", opc); output_loc_operands_raw (loc); if (!loc->dw_loc_next) @@ -5451,14 +5516,16 @@ output_loc_sequence_raw (dw_loc_descr_ref loc) description based on a cfi entry with a complex address. */ static void -output_cfa_loc (dw_cfi_ref cfi) +output_cfa_loc (dw_cfi_ref cfi, int for_eh) { dw_loc_descr_ref loc; unsigned long size; if (cfi->dw_cfi_opc == DW_CFA_expression) { - dw2_asm_output_data (1, cfi->dw_cfi_oprnd1.dw_cfi_reg_num, NULL); + unsigned r = + DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh); + dw2_asm_output_data (1, r, NULL); loc = cfi->dw_cfi_oprnd2.dw_cfi_loc; } else @@ -5469,7 +5536,7 @@ output_cfa_loc (dw_cfi_ref cfi) dw2_asm_output_data_uleb128 (size, NULL); /* Now output the operations themselves. */ - output_loc_sequence (loc); + output_loc_sequence (loc, for_eh); } /* Similar, but used for .cfi_escape. */ @@ -5482,7 +5549,9 @@ output_cfa_loc_raw (dw_cfi_ref cfi) if (cfi->dw_cfi_opc == DW_CFA_expression) { - fprintf (asm_out_file, "%#x,", cfi->dw_cfi_oprnd1.dw_cfi_reg_num); + unsigned r = + DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); + fprintf (asm_out_file, "%#x,", r); loc = cfi->dw_cfi_oprnd2.dw_cfi_loc; } else @@ -5680,10 +5749,6 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, dw_die_ref); static void dwarf2out_abstract_function (tree); static void dwarf2out_var_location (rtx); -static void dwarf2out_direct_call (tree); -static void dwarf2out_virtual_call_token (tree, int); -static void dwarf2out_copy_call_info (rtx, rtx); -static void dwarf2out_virtual_call (int); static void dwarf2out_begin_function (tree); static void dwarf2out_set_name (tree, tree); @@ -5726,10 +5791,6 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = debug_nothing_int, /* handle_pch */ dwarf2out_var_location, dwarf2out_switch_text_section, - dwarf2out_direct_call, - dwarf2out_virtual_call_token, - dwarf2out_copy_call_info, - dwarf2out_virtual_call, dwarf2out_set_name, 1, /* start_end_main_source_file */ TYPE_SYMTAB_IS_DIE /* tree_type_symtab_field */ @@ -5744,6 +5805,16 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = representation is done after the entire program has been compiled. The types below are used to describe the internal representation. */ +/* Whether to put type DIEs into their own section .debug_types instead + of making them part of the .debug_info section. Only supported for + Dwarf V4 or higher and the user didn't disable them through + -fno-debug-types-section. It is more efficient to put them in a + separate comdat sections since the linker will then be able to + remove duplicates. But not all tools support .debug_types sections + yet. */ + +#define use_debug_types (dwarf_version >= 4 && flag_debug_types_section) + /* Various DIE's use offsets relative to the beginning of the .debug_info section to refer to each other. */ @@ -5753,31 +5824,70 @@ typedef long int dw_offset; typedef struct dw_attr_struct *dw_attr_ref; typedef struct dw_line_info_struct *dw_line_info_ref; -typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref; typedef struct pubname_struct *pubname_ref; typedef struct dw_ranges_struct *dw_ranges_ref; typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref; typedef struct comdat_type_struct *comdat_type_node_ref; -/* Each entry in the line_info_table maintains the file and - line number associated with the label generated for that - entry. The label gives the PC value associated with - the line number entry. */ +/* The entries in the line_info table more-or-less mirror the opcodes + that are used in the real dwarf line table. Arrays of these entries + are collected per section when DWARF2_ASM_LINE_DEBUG_INFO is not + supported. */ + +enum dw_line_info_opcode { + /* Emit DW_LNE_set_address; the operand is the label index. */ + LI_set_address, + + /* Emit a row to the matrix with the given line. This may be done + via any combination of DW_LNS_copy, DW_LNS_advance_line, and + special opcodes. */ + LI_set_line, + + /* Emit a DW_LNS_set_file. */ + LI_set_file, + + /* Emit a DW_LNS_set_column. */ + LI_set_column, + + /* Emit a DW_LNS_negate_stmt; the operand is ignored. */ + LI_negate_stmt, + + /* Emit a DW_LNS_set_prologue_end/epilogue_begin; the operand is ignored. */ + LI_set_prologue_end, + LI_set_epilogue_begin, + + /* Emit a DW_LNE_set_discriminator. */ + LI_set_discriminator +}; typedef struct GTY(()) dw_line_info_struct { - unsigned long dw_file_num; - unsigned long dw_line_num; -} -dw_line_info_entry; + enum dw_line_info_opcode opcode; + unsigned int val; +} dw_line_info_entry; -/* Line information for functions in separate sections; each one gets its - own sequence. */ -typedef struct GTY(()) dw_separate_line_info_struct { - unsigned long dw_file_num; - unsigned long dw_line_num; - unsigned long function; -} -dw_separate_line_info_entry; +DEF_VEC_O(dw_line_info_entry); +DEF_VEC_ALLOC_O(dw_line_info_entry, gc); + +typedef struct GTY(()) dw_line_info_table_struct { + /* The label that marks the end of this section. */ + const char *end_label; + + /* The values for the last row of the matrix, as collected in the table. + These are used to minimize the changes to the next row. */ + unsigned int file_num; + unsigned int line_num; + unsigned int column_num; + int discrim_num; + bool is_stmt; + bool in_use; + + VEC(dw_line_info_entry, gc) *entries; +} dw_line_info_table; + +typedef dw_line_info_table *dw_line_info_table_p; + +DEF_VEC_P(dw_line_info_table_p); +DEF_VEC_ALLOC_P(dw_line_info_table_p, gc); /* Each DIE attribute has a field specifying the attribute kind, a link to the next attribute in the chain, and an attribute value. @@ -5802,7 +5912,7 @@ typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct { char * GTY ((tag ("0"))) die_symbol; comdat_type_node_ref GTY ((tag ("1"))) die_type_node; } - GTY ((desc ("dwarf_version >= 4"))) die_id; + GTY ((desc ("use_debug_types"))) die_id; VEC(dw_attr_node,gc) * die_attr; dw_die_ref die_parent; dw_die_ref die_child; @@ -5879,7 +5989,7 @@ typedef struct GTY(()) limbo_die_struct { } limbo_die_node; -typedef struct GTY(()) skeleton_chain_struct +typedef struct skeleton_chain_struct { dw_die_ref old_die; dw_die_ref new_die; @@ -5955,7 +6065,7 @@ skeleton_chain_node; #define DWARF_LINE_BASE -10 /* First special line opcode - leave room for the standard opcodes. */ -#define DWARF_LINE_OPCODE_BASE 10 +#define DWARF_LINE_OPCODE_BASE ((int)DW_LNS_set_isa + 1) /* Range of line offsets in a special line info. opcode. */ #define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1) @@ -6034,15 +6144,56 @@ struct GTY (()) var_loc_list_def { Do not mark it for GC because it is marked through the chain. */ struct var_loc_node * GTY ((skip ("%h"))) last; + /* Pointer to the last element before section switch, + if NULL, either sections weren't switched or first + is after section switch. */ + struct var_loc_node * GTY ((skip ("%h"))) last_before_switch; + /* DECL_UID of the variable decl. */ unsigned int decl_id; }; typedef struct var_loc_list_def var_loc_list; +/* Call argument location list. */ +struct GTY ((chain_next ("%h.next"))) call_arg_loc_node { + rtx GTY (()) call_arg_loc_note; + const char * GTY (()) label; + tree GTY (()) block; + bool tail_call_p; + rtx GTY (()) symbol_ref; + struct call_arg_loc_node * GTY (()) next; +}; + /* Table of decl location linked lists. */ static GTY ((param_is (var_loc_list))) htab_t decl_loc_table; +/* Head and tail of call_arg_loc chain. */ +static GTY (()) struct call_arg_loc_node *call_arg_locations; +static struct call_arg_loc_node *call_arg_loc_last; + +/* Number of call sites in the current function. */ +static int call_site_count = -1; +/* Number of tail call sites in the current function. */ +static int tail_call_site_count = -1; + +/* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine} + DIEs. */ +static VEC (dw_die_ref, heap) *block_map; + +/* A cached location list. */ +struct GTY (()) cached_dw_loc_list_def { + /* The DECL_UID of the decl that this entry describes. */ + unsigned int decl_id; + + /* The cached location list. */ + dw_loc_list_ref loc_list; +}; +typedef struct cached_dw_loc_list_def cached_dw_loc_list; + +/* Table of cached location lists. */ +static GTY ((param_is (cached_dw_loc_list))) htab_t cached_dw_loc_list_table; + /* A pointer to the base of a list of references to DIE's that are uniquely identified by their tag, presence/absence of children DIE's, and list of attribute/value pairs. */ @@ -6059,31 +6210,20 @@ static GTY(()) unsigned abbrev_die_table_in_use; abbrev_die_table. */ #define ABBREV_DIE_TABLE_INCREMENT 256 -/* A pointer to the base of a table that contains line information - for each source code line in .text in the compilation unit. */ -static GTY((length ("line_info_table_allocated"))) - dw_line_info_ref line_info_table; - -/* Number of elements currently allocated for line_info_table. */ -static GTY(()) unsigned line_info_table_allocated; - -/* Number of elements in line_info_table currently in use. */ -static GTY(()) unsigned line_info_table_in_use; - -/* A pointer to the base of a table that contains line information - for each source code line outside of .text in the compilation unit. */ -static GTY ((length ("separate_line_info_table_allocated"))) - dw_separate_line_info_ref separate_line_info_table; +/* A global counter for generating labels for line number data. */ +static unsigned int line_info_label_num; -/* Number of elements currently allocated for separate_line_info_table. */ -static GTY(()) unsigned separate_line_info_table_allocated; +/* The current table to which we should emit line number information + for the current function. This will be set up at the beginning of + assembly for the function. */ +static dw_line_info_table *cur_line_info_table; -/* Number of elements in separate_line_info_table currently in use. */ -static GTY(()) unsigned separate_line_info_table_in_use; +/* The two default tables of line number info. */ +static GTY(()) dw_line_info_table *text_section_line_info; +static GTY(()) dw_line_info_table *cold_text_section_line_info; -/* Size (in elements) of increments by which we may expand the - line_info_table. */ -#define LINE_INFO_TABLE_INCREMENT 1024 +/* The set of all non-default tables of line number info. */ +static GTY(()) VEC (dw_line_info_table_p, gc) *separate_line_info; /* A flag to tell pubnames/types export if there is an info section to refer to. */ @@ -6101,19 +6241,6 @@ static GTY (()) VEC (pubname_entry, gc) * pubtype_table; defines/undefines (and file start/end markers). */ static GTY (()) VEC (macinfo_entry, gc) * macinfo_table; -/* Array of dies for which we should generate .debug_arange info. */ -static GTY((length ("arange_table_allocated"))) dw_die_ref *arange_table; - -/* Number of elements currently allocated for arange_table. */ -static GTY(()) unsigned arange_table_allocated; - -/* Number of elements in arange_table currently in use. */ -static GTY(()) unsigned arange_table_in_use; - -/* Size (in elements) of increments by which we may expand the - arange_table. */ -#define ARANGE_TABLE_INCREMENT 64 - /* Array of dies for which we should generate .debug_ranges info. */ static GTY ((length ("ranges_table_allocated"))) dw_ranges_ref ranges_table; @@ -6146,42 +6273,6 @@ static GTY(()) unsigned int loclabel_num; /* Unique label counter for point-of-call tables. */ static GTY(()) unsigned int poc_label_num; -/* The direct call table structure. */ - -typedef struct GTY(()) dcall_struct { - unsigned int poc_label_num; - tree poc_decl; - dw_die_ref targ_die; -} -dcall_entry; - -DEF_VEC_O(dcall_entry); -DEF_VEC_ALLOC_O(dcall_entry, gc); - -/* The virtual call table structure. */ - -typedef struct GTY(()) vcall_struct { - unsigned int poc_label_num; - unsigned int vtable_slot; -} -vcall_entry; - -DEF_VEC_O(vcall_entry); -DEF_VEC_ALLOC_O(vcall_entry, gc); - -/* Pointers to the direct and virtual call tables. */ -static GTY (()) VEC (dcall_entry, gc) * dcall_table = NULL; -static GTY (()) VEC (vcall_entry, gc) * vcall_table = NULL; - -/* A hash table to map INSN_UIDs to vtable slot indexes. */ - -struct GTY (()) vcall_insn { - int insn_uid; - unsigned int vtable_slot; -}; - -static GTY ((param_is (struct vcall_insn))) htab_t vcall_insn_table; - /* Record whether the function being analyzed contains inlined functions. */ static int current_function_has_inlines; @@ -6196,6 +6287,12 @@ static GTY(()) struct dwarf_file_data * file_table_last_lookup; static GTY(()) VEC(die_arg_entry,gc) *tmpl_value_parm_die_table; +/* Instances of generic types for which we need to generate debug + info that describe their generic parameters and arguments. That + generation needs to happen once all types are properly laid out so + we do it at the end of compilation. */ +static GTY(()) VEC(tree,gc) *generic_type_instances; + /* Offset from the "steady-state frame pointer" to the frame base, within the current function. */ static HOST_WIDE_INT frame_pointer_fb_offset; @@ -6264,6 +6361,8 @@ static void remove_child_TAG (dw_die_ref, enum dwarf_tag); static void add_child_die (dw_die_ref, dw_die_ref); static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree); static dw_die_ref lookup_type_die (tree); +static dw_die_ref strip_naming_typedef (tree, dw_die_ref); +static dw_die_ref lookup_type_die_strip_naming_typedef (tree); static void equate_type_number_to_die (tree, dw_die_ref); static hashval_t decl_die_table_hash (const void *); static int decl_die_table_eq (const void *, const void *); @@ -6277,7 +6376,6 @@ static void equate_decl_number_to_die (tree, dw_die_ref); static struct var_loc_node *add_var_loc_to_decl (tree, rtx, const char *); static void print_spaces (FILE *); static void print_die (dw_die_ref, FILE *); -static void print_dwarf_line_table (FILE *); static dw_die_ref push_new_compile_unit (dw_die_ref, dw_die_ref); static dw_die_ref pop_compile_unit (dw_die_ref); static void loc_checksum (dw_loc_descr_ref, struct md5_ctx *); @@ -6349,13 +6447,13 @@ static void add_pubname (tree, dw_die_ref); static void add_pubname_string (const char *, dw_die_ref); static void add_pubtype (tree, dw_die_ref); static void output_pubnames (VEC (pubname_entry,gc) *); -static void add_arange (tree, dw_die_ref); -static void output_aranges (void); +static void output_aranges (unsigned long); static unsigned int add_ranges_num (int); static unsigned int add_ranges (const_tree); static void add_ranges_by_labels (dw_die_ref, const char *, const char *, bool *); static void output_ranges (void); +static dw_line_info_table *new_line_info_table (void); static void output_line_info (void); static void output_file_names (void); static dw_die_ref base_type_die (tree); @@ -6396,11 +6494,12 @@ static void insert_int (HOST_WIDE_INT, unsigned, unsigned char *); static void insert_double (double_int, unsigned char *); static void insert_float (const_rtx, unsigned char *); static rtx rtl_for_decl_location (tree); -static bool add_location_or_const_value_attribute (dw_die_ref, tree, +static bool add_location_or_const_value_attribute (dw_die_ref, tree, bool, enum dwarf_attribute); static bool tree_add_const_value_attribute (dw_die_ref, tree); static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree); static void add_name_attribute (dw_die_ref, const char *); +static void add_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref); static void add_comp_dir_attribute (dw_die_ref); static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree); static void add_subscript_info (dw_die_ref, tree, bool); @@ -6476,6 +6575,7 @@ static void output_loc_list (dw_loc_list_ref); static char *gen_internal_sym (const char *); static void prune_unmark_dies (dw_die_ref); +static void prune_unused_types_mark_generic_parms_dies (dw_die_ref); static void prune_unused_types_mark (dw_die_ref, int); static void prune_unused_types_walk (dw_die_ref); static void prune_unused_types_walk_attribs (dw_die_ref); @@ -6488,6 +6588,9 @@ static inline void add_AT_vms_delta (dw_die_ref, enum dwarf_attribute, const char *, const char *); static void append_entry_to_tmpl_value_parm_die_table (dw_die_ref, tree); static void gen_remaining_tmpl_value_param_die_attribute (void); +static bool generic_type_p (tree); +static void schedule_generic_params_dies_gen (tree t); +static void gen_scheduled_generic_parms_dies (void); /* Section names used to hold DWARF debugging information. */ #ifndef DEBUG_INFO_SECTION @@ -6514,12 +6617,6 @@ static void gen_remaining_tmpl_value_param_die_attribute (void); #ifndef DEBUG_PUBTYPES_SECTION #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes" #endif -#ifndef DEBUG_DCALL_SECTION -#define DEBUG_DCALL_SECTION ".debug_dcall" -#endif -#ifndef DEBUG_VCALL_SECTION -#define DEBUG_VCALL_SECTION ".debug_vcall" -#endif #ifndef DEBUG_STR_SECTION #define DEBUG_STR_SECTION ".debug_str" #endif @@ -6599,9 +6696,6 @@ static char ranges_section_label[2 * MAX_ARTIFICIAL_LABEL_BYTES]; #ifndef LINE_CODE_LABEL #define LINE_CODE_LABEL "LM" #endif -#ifndef SEPARATE_LINE_CODE_LABEL -#define SEPARATE_LINE_CODE_LABEL "LSM" -#endif /* Return the root of the DIE's built for the current compilation unit. */ @@ -6820,6 +6914,10 @@ dwarf_tag_name (unsigned int tag) return "DW_TAG_GNU_EINCL"; case DW_TAG_GNU_template_template_param: return "DW_TAG_GNU_template_template_param"; + case DW_TAG_GNU_call_site: + return "DW_TAG_GNU_call_site"; + case DW_TAG_GNU_call_site_parameter: + return "DW_TAG_GNU_call_site_parameter"; default: return "DW_TAG_"; } @@ -7044,6 +7142,7 @@ dwarf_attr_name (unsigned int attr) return "DW_AT_body_begin"; case DW_AT_body_end: return "DW_AT_body_end"; + case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; case DW_AT_GNU_guarded_by: @@ -7064,6 +7163,25 @@ dwarf_attr_name (unsigned int attr) return "DW_AT_GNU_odr_signature"; case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name"; + case DW_AT_GNU_call_site_value: + return "DW_AT_GNU_call_site_value"; + case DW_AT_GNU_call_site_data_value: + return "DW_AT_GNU_call_site_data_value"; + case DW_AT_GNU_call_site_target: + return "DW_AT_GNU_call_site_target"; + case DW_AT_GNU_call_site_target_clobbered: + return "DW_AT_GNU_call_site_target_clobbered"; + case DW_AT_GNU_tail_call: + return "DW_AT_GNU_tail_call"; + case DW_AT_GNU_all_tail_call_sites: + return "DW_AT_GNU_all_tail_call_sites"; + case DW_AT_GNU_all_call_sites: + return "DW_AT_GNU_all_call_sites"; + case DW_AT_GNU_all_source_call_sites: + return "DW_AT_GNU_all_source_call_sites"; + + case DW_AT_GNAT_descriptive_type: + return "DW_AT_GNAT_descriptive_type"; case DW_AT_VMS_rtnbeg_pd_address: return "DW_AT_VMS_rtnbeg_pd_address"; @@ -8033,6 +8151,39 @@ lookup_type_die (tree type) return TYPE_SYMTAB_DIE (type); } +/* Given a TYPE_DIE representing the type TYPE, if TYPE is an + anonymous type named by the typedef TYPE_DIE, return the DIE of the + anonymous type instead the one of the naming typedef. */ + +static inline dw_die_ref +strip_naming_typedef (tree type, dw_die_ref type_die) +{ + if (type + && TREE_CODE (type) == RECORD_TYPE + && type_die + && type_die->die_tag == DW_TAG_typedef + && is_naming_typedef_decl (TYPE_NAME (type))) + type_die = get_AT_ref (type_die, DW_AT_type); + return type_die; +} + +/* Like lookup_type_die, but if type is an anonymous type named by a + typedef[1], return the DIE of the anonymous type instead the one of + the naming typedef. This is because in gen_typedef_die, we did + equate the anonymous struct named by the typedef with the DIE of + the naming typedef. So by default, lookup_type_die on an anonymous + struct yields the DIE of the naming typedef. + + [1]: Read the comment of is_naming_typedef_decl to learn about what + a naming typedef is. */ + +static inline dw_die_ref +lookup_type_die_strip_naming_typedef (tree type) +{ + dw_die_ref die = lookup_type_die (type); + return strip_naming_typedef (type, die); +} + /* Equate a DIE to a given type specifier. */ static inline void @@ -8093,6 +8244,24 @@ lookup_decl_loc (const_tree decl) htab_find_with_hash (decl_loc_table, decl, DECL_UID (decl)); } +/* Returns a hash value for X (which really is a cached_dw_loc_list_list). */ + +static hashval_t +cached_dw_loc_list_table_hash (const void *x) +{ + return (hashval_t) ((const cached_dw_loc_list *) x)->decl_id; +} + +/* Return nonzero if decl_id of cached_dw_loc_list X is the same as + UID of decl *Y. */ + +static int +cached_dw_loc_list_table_eq (const void *x, const void *y) +{ + return (((const cached_dw_loc_list *) x)->decl_id + == DECL_UID ((const_tree) y)); +} + /* Equate a DIE to a particular declaration. */ static void @@ -8428,12 +8597,15 @@ print_die (dw_die_ref die, FILE *outfile) unsigned ix; print_spaces (outfile); - fprintf (outfile, "DIE %4ld: %s\n", - die->die_offset, dwarf_tag_name (die->die_tag)); + fprintf (outfile, "DIE %4ld: %s (%p)\n", + die->die_offset, dwarf_tag_name (die->die_tag), + (void*) die); print_spaces (outfile); fprintf (outfile, " abbrev id: %lu", die->die_abbrev); - fprintf (outfile, " offset: %ld\n", die->die_offset); - if (dwarf_version >= 4 && die->die_id.die_type_node) + fprintf (outfile, " offset: %ld", die->die_offset); + fprintf (outfile, " mark: %d\n", die->die_mark); + + if (use_debug_types && die->die_id.die_type_node) { print_spaces (outfile); fprintf (outfile, " signature: "); @@ -8485,17 +8657,18 @@ print_die (dw_die_ref die, FILE *outfile) case dw_val_class_die_ref: if (AT_ref (a) != NULL) { - if (dwarf_version >= 4 && AT_ref (a)->die_id.die_type_node) + if (use_debug_types && AT_ref (a)->die_id.die_type_node) { fprintf (outfile, "die -> signature: "); print_signature (outfile, AT_ref (a)->die_id.die_type_node->signature); } - else if (dwarf_version < 4 && AT_ref (a)->die_id.die_symbol) + else if (! use_debug_types && AT_ref (a)->die_id.die_symbol) fprintf (outfile, "die -> label: %s", AT_ref (a)->die_id.die_symbol); else fprintf (outfile, "die -> %ld", AT_ref (a)->die_offset); + fprintf (outfile, " (%p)", (void *) AT_ref (a)); } else fprintf (outfile, "die -> "); @@ -8544,27 +8717,6 @@ print_die (dw_die_ref die, FILE *outfile) fprintf (outfile, "\n"); } -/* Print the contents of the source code line number correspondence table. - This routine is a debugging aid only. */ - -static void -print_dwarf_line_table (FILE *outfile) -{ - unsigned i; - dw_line_info_ref line_info; - - fprintf (outfile, "\n\nDWARF source line information\n"); - for (i = 1; i < line_info_table_in_use; i++) - { - line_info = &line_info_table[i]; - fprintf (outfile, "%5d: %4ld %6ld\n", i, - line_info->dw_file_num, - line_info->dw_line_num); - } - - fprintf (outfile, "\n\n"); -} - /* Print the information collected for a given DIE. */ DEBUG_FUNCTION void @@ -8581,8 +8733,6 @@ debug_dwarf (void) { print_indent = 0; print_die (comp_unit_die (), stderr); - if (! DWARF2_ASM_LINE_DEBUG_INFO) - print_dwarf_line_table (stderr); } /* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU @@ -10447,7 +10597,7 @@ build_abbrev_table (dw_die_ref die) if (AT_class (a) == dw_val_class_die_ref && AT_ref (a)->die_mark == 0) { - gcc_assert (dwarf_version >= 4 || AT_ref (a)->die_id.die_symbol); + gcc_assert (use_debug_types || AT_ref (a)->die_id.die_symbol); set_AT_ref_external (a, 1); } @@ -10591,11 +10741,11 @@ size_of_die (dw_die_ref die) case dw_val_class_die_ref: if (AT_ref_external (a)) { - /* In DWARF4, we use DW_FORM_sig8; for earlier versions + /* In DWARF4, we use DW_FORM_ref_sig8; for earlier versions we use DW_FORM_ref_addr. In DWARF2, DW_FORM_ref_addr is sized by target address length, whereas in DWARF3 it's always sized as an offset. */ - if (dwarf_version >= 4) + if (use_debug_types) size += DWARF_TYPE_SIGNATURE_SIZE; else if (dwarf_version == 2) size += DWARF2_ADDR_SIZE; @@ -10681,7 +10831,7 @@ unmark_dies (dw_die_ref die) { dw_die_ref c; - if (dwarf_version < 4) + if (! use_debug_types) gcc_assert (die->die_mark); die->die_mark = 0; @@ -10743,7 +10893,20 @@ size_of_aranges (void) size += 2 * DWARF2_ADDR_SIZE; if (cold_text_section_used) size += 2 * DWARF2_ADDR_SIZE; - size += 2 * DWARF2_ADDR_SIZE * arange_table_in_use; + if (have_multiple_function_sections) + { + unsigned fde_idx = 0; + + for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++) + { + dw_fde_ref fde = &fde_table[fde_idx]; + + if (!fde->in_std_section) + size += 2 * DWARF2_ADDR_SIZE; + if (fde->dw_fde_second_begin && !fde->second_in_std_section) + size += 2 * DWARF2_ADDR_SIZE; + } + } /* Count the two zero words used to terminated the address range table. */ size += 2 * DWARF2_ADDR_SIZE; @@ -10867,7 +11030,7 @@ value_format (dw_attr_ref a) return DW_FORM_flag; case dw_val_class_die_ref: if (AT_ref_external (a)) - return dwarf_version >= 4 ? DW_FORM_sig8 : DW_FORM_ref_addr; + return use_debug_types ? DW_FORM_ref_sig8 : DW_FORM_ref_addr; else return DW_FORM_ref; case dw_val_class_fde_ref: @@ -10918,6 +11081,9 @@ output_abbrev_section (void) { unsigned long abbrev_id; + if (abbrev_die_table_in_use == 1) + return; + for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id) { dw_die_ref abbrev = abbrev_die_table[abbrev_id]; @@ -11039,7 +11205,7 @@ output_loc_list (dw_loc_list_ref list_head) gcc_assert (size <= 0xffff); dw2_asm_output_data (2, size, "%s", "Location expression size"); - output_loc_sequence (curr->expr); + output_loc_sequence (curr->expr, -1); } dw2_asm_output_data (DWARF2_ADDR_SIZE, 0, @@ -11074,7 +11240,7 @@ output_die (dw_die_ref die) /* If someone in another CU might refer to us, set up a symbol for them to point to. */ - if (dwarf_version < 4 && die->die_id.die_symbol) + if (! use_debug_types && die->die_id.die_symbol) output_die_symbol (die); dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)", @@ -11117,7 +11283,7 @@ output_die (dw_die_ref die) else dw2_asm_output_data (constant_size (size), size, "%s", name); - output_loc_sequence (AT_loc (a)); + output_loc_sequence (AT_loc (a), -1); break; case dw_val_class_const: @@ -11213,7 +11379,7 @@ output_die (dw_die_ref die) case dw_val_class_die_ref: if (AT_ref_external (a)) { - if (dwarf_version >= 4) + if (use_debug_types) { comdat_type_node_ref type_node = AT_ref (a)->die_id.die_type_node; @@ -11571,35 +11737,14 @@ output_pubnames (VEC (pubname_entry, gc) * names) dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, NULL); } -/* Add a new entry to .debug_aranges if appropriate. */ - -static void -add_arange (tree decl, dw_die_ref die) -{ - if (! DECL_SECTION_NAME (decl)) - return; - - if (arange_table_in_use == arange_table_allocated) - { - arange_table_allocated += ARANGE_TABLE_INCREMENT; - arange_table = GGC_RESIZEVEC (dw_die_ref, arange_table, - arange_table_allocated); - memset (arange_table + arange_table_in_use, 0, - ARANGE_TABLE_INCREMENT * sizeof (dw_die_ref)); - } - - arange_table[arange_table_in_use++] = die; -} - /* Output the information that goes into the .debug_aranges table. Namely, define the beginning and ending address range of the text section generated for this compilation unit. */ static void -output_aranges (void) +output_aranges (unsigned long aranges_length) { unsigned i; - unsigned long aranges_length = size_of_aranges (); if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) dw2_asm_output_data (4, 0xffffffff, @@ -11644,38 +11789,28 @@ output_aranges (void) cold_text_section_label, "Length"); } - for (i = 0; i < arange_table_in_use; i++) + if (have_multiple_function_sections) { - dw_die_ref die = arange_table[i]; - - /* We shouldn't see aranges for DIEs outside of the main CU. */ - gcc_assert (die->die_mark); + unsigned fde_idx = 0; - if (die->die_tag == DW_TAG_subprogram) - { - dw2_asm_output_addr (DWARF2_ADDR_SIZE, get_AT_low_pc (die), - "Address"); - dw2_asm_output_delta (DWARF2_ADDR_SIZE, get_AT_hi_pc (die), - get_AT_low_pc (die), "Length"); - } - else + for (fde_idx = 0; fde_idx < fde_table_in_use; fde_idx++) { - /* A static variable; extract the symbol from DW_AT_location. - Note that this code isn't currently hit, as we only emit - aranges for functions (jason 9/23/99). */ - dw_attr_ref a = get_AT (die, DW_AT_location); - dw_loc_descr_ref loc; - - gcc_assert (a && AT_class (a) == dw_val_class_loc); - - loc = AT_loc (a); - gcc_assert (loc->dw_loc_opc == DW_OP_addr); - - dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, - loc->dw_loc_oprnd1.v.val_addr, "Address"); - dw2_asm_output_data (DWARF2_ADDR_SIZE, - get_AT_unsigned (die, DW_AT_byte_size), - "Length"); + dw_fde_ref fde = &fde_table[fde_idx]; + + if (!fde->in_std_section) + { + dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin, + "Address"); + dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_end, + fde->dw_fde_begin, "Length"); + } + if (fde->dw_fde_second_begin && !fde->second_in_std_section) + { + dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_second_begin, + "Address"); + dw2_asm_output_delta (DWARF2_ADDR_SIZE, fde->dw_fde_second_end, + fde->dw_fde_second_begin, "Length"); + } } } @@ -12166,56 +12301,157 @@ output_file_names (void) } -/* Output the source line number correspondence information. This - information goes into the .debug_line section. */ +/* Output one line number table into the .debug_line section. */ static void -output_line_info (void) +output_one_line_info_table (dw_line_info_table *table) { - char l1[20], l2[20], p1[20], p2[20]; char line_label[MAX_ARTIFICIAL_LABEL_BYTES]; - char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES]; - unsigned opc; - unsigned n_op_args; - unsigned long lt_index; - unsigned long current_line; - long line_offset; - long line_delta; - unsigned long current_file; - unsigned long function; - int ver = dwarf_version; - - ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0); - ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0); - ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0); - ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0); + unsigned int current_line = 1; + bool current_is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START; + dw_line_info_entry *ent; + size_t i; - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) - dw2_asm_output_data (4, 0xffffffff, - "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, - "Length of Source Line Info"); - ASM_OUTPUT_LABEL (asm_out_file, l1); + FOR_EACH_VEC_ELT (dw_line_info_entry, table->entries, i, ent) + { + switch (ent->opcode) + { + case LI_set_address: + /* ??? Unfortunately, we have little choice here currently, and + must always use the most general form. GCC does not know the + address delta itself, so we can't use DW_LNS_advance_pc. Many + ports do have length attributes which will give an upper bound + on the address range. We could perhaps use length attributes + to determine when it is safe to use DW_LNS_fixed_advance_pc. */ + ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, ent->val); - dw2_asm_output_data (2, ver, "DWARF Version"); - dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length"); - ASM_OUTPUT_LABEL (asm_out_file, p1); + /* This can handle any delta. This takes + 4+DWARF2_ADDR_SIZE bytes. */ + dw2_asm_output_data (1, 0, "set address %s", line_label); + dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); + dw2_asm_output_data (1, DW_LNE_set_address, NULL); + dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL); + break; - /* Define the architecture-dependent minimum instruction length (in - bytes). In this implementation of DWARF, this field is used for - information purposes only. Since GCC generates assembly language, - we have no a priori knowledge of how many instruction bytes are - generated for each source line, and therefore can use only the - DW_LNE_set_address and DW_LNS_fixed_advance_pc line information - commands. Accordingly, we fix this as `1', which is "correct - enough" for all architectures, and don't let the target override. */ - dw2_asm_output_data (1, 1, - "Minimum Instruction Length"); + case LI_set_line: + if (ent->val == current_line) + { + /* We still need to start a new row, so output a copy insn. */ + dw2_asm_output_data (1, DW_LNS_copy, + "copy line %u", current_line); + } + else + { + int line_offset = ent->val - current_line; + int line_delta = line_offset - DWARF_LINE_BASE; - if (ver >= 4) - dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN, - "Maximum Operations Per Instruction"); - dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START, + current_line = ent->val; + if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) + { + /* This can handle deltas from -10 to 234, using the current + definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. + This takes 1 byte. */ + dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta, + "line %u", current_line); + } + else + { + /* This can handle any delta. This takes at least 4 bytes, + depending on the value being encoded. */ + dw2_asm_output_data (1, DW_LNS_advance_line, + "advance to line %u", current_line); + dw2_asm_output_data_sleb128 (line_offset, NULL); + dw2_asm_output_data (1, DW_LNS_copy, NULL); + } + } + break; + + case LI_set_file: + dw2_asm_output_data (1, DW_LNS_set_file, "set file %u", ent->val); + dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val); + break; + + case LI_set_column: + dw2_asm_output_data (1, DW_LNS_set_column, "column %u", ent->val); + dw2_asm_output_data_uleb128 (ent->val, "%u", ent->val); + break; + + case LI_negate_stmt: + current_is_stmt = !current_is_stmt; + dw2_asm_output_data (1, DW_LNS_negate_stmt, + "is_stmt %d", current_is_stmt); + break; + + case LI_set_prologue_end: + dw2_asm_output_data (1, DW_LNS_set_prologue_end, + "set prologue end"); + break; + + case LI_set_epilogue_begin: + dw2_asm_output_data (1, DW_LNS_set_epilogue_begin, + "set epilogue begin"); + break; + + case LI_set_discriminator: + dw2_asm_output_data (1, 0, "discriminator %u", ent->val); + dw2_asm_output_data_uleb128 (1 + size_of_uleb128 (ent->val), NULL); + dw2_asm_output_data (1, DW_LNE_set_discriminator, NULL); + dw2_asm_output_data_uleb128 (ent->val, NULL); + break; + } + } + + /* Emit debug info for the address of the end of the table. */ + dw2_asm_output_data (1, 0, "set address %s", table->end_label); + dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); + dw2_asm_output_data (1, DW_LNE_set_address, NULL); + dw2_asm_output_addr (DWARF2_ADDR_SIZE, table->end_label, NULL); + + dw2_asm_output_data (1, 0, "end sequence"); + dw2_asm_output_data_uleb128 (1, NULL); + dw2_asm_output_data (1, DW_LNE_end_sequence, NULL); +} + +/* Output the source line number correspondence information. This + information goes into the .debug_line section. */ + +static void +output_line_info (void) +{ + char l1[20], l2[20], p1[20], p2[20]; + int ver = dwarf_version; + int opc; + + ASM_GENERATE_INTERNAL_LABEL (l1, LINE_NUMBER_BEGIN_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (l2, LINE_NUMBER_END_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (p1, LN_PROLOG_AS_LABEL, 0); + ASM_GENERATE_INTERNAL_LABEL (p2, LN_PROLOG_END_LABEL, 0); + + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + dw2_asm_output_delta (DWARF_OFFSET_SIZE, l2, l1, + "Length of Source Line Info"); + ASM_OUTPUT_LABEL (asm_out_file, l1); + + dw2_asm_output_data (2, ver, "DWARF Version"); + dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length"); + ASM_OUTPUT_LABEL (asm_out_file, p1); + + /* Define the architecture-dependent minimum instruction length (in bytes). + In this implementation of DWARF, this field is used for information + purposes only. Since GCC generates assembly language, we have no + a priori knowledge of how many instruction bytes are generated for each + source line, and therefore can use only the DW_LNE_set_address and + DW_LNS_fixed_advance_pc line information commands. Accordingly, we fix + this as '1', which is "correct enough" for all architectures, + and don't let the target override. */ + dw2_asm_output_data (1, 1, "Minimum Instruction Length"); + + if (ver >= 4) + dw2_asm_output_data (1, DWARF_LINE_DEFAULT_MAX_OPS_PER_INSN, + "Maximum Operations Per Instruction"); + dw2_asm_output_data (1, DWARF_LINE_DEFAULT_IS_STMT_START, "Default is_stmt_start flag"); dw2_asm_output_data (1, DWARF_LINE_BASE, "Line Base Value (Special Opcodes)"); @@ -12226,6 +12462,7 @@ output_line_info (void) for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; opc++) { + int n_op_args; switch (opc) { case DW_LNS_advance_pc: @@ -12233,6 +12470,7 @@ output_line_info (void) case DW_LNS_set_file: case DW_LNS_set_column: case DW_LNS_fixed_advance_pc: + case DW_LNS_set_isa: n_op_args = 1; break; default: @@ -12248,364 +12486,24 @@ output_line_info (void) output_file_names (); ASM_OUTPUT_LABEL (asm_out_file, p2); - /* We used to set the address register to the first location in the text - section here, but that didn't accomplish anything since we already - have a line note for the opening brace of the first function. */ - - /* Generate the line number to PC correspondence table, encoded as - a series of state machine operations. */ - current_file = 1; - current_line = 1; - - if (cfun && in_cold_section_p) - strcpy (prev_line_label, crtl->subsections.cold_section_label); - else - strcpy (prev_line_label, text_section_label); - for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index) - { - dw_line_info_ref line_info = &line_info_table[lt_index]; - -#if 0 - /* Disable this optimization for now; GDB wants to see two line notes - at the beginning of a function so it can find the end of the - prologue. */ - - /* Don't emit anything for redundant notes. Just updating the - address doesn't accomplish anything, because we already assume - that anything after the last address is this line. */ - if (line_info->dw_line_num == current_line - && line_info->dw_file_num == current_file) - continue; -#endif - - /* Emit debug info for the address of the current line. - - Unfortunately, we have little choice here currently, and must always - use the most general form. GCC does not know the address delta - itself, so we can't use DW_LNS_advance_pc. Many ports do have length - attributes which will give an upper bound on the address range. We - could perhaps use length attributes to determine when it is safe to - use DW_LNS_fixed_advance_pc. */ - - ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index); - if (0) - { - /* This can handle deltas up to 0xffff. This takes 3 bytes. */ - dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, - "DW_LNS_fixed_advance_pc"); - dw2_asm_output_delta (2, line_label, prev_line_label, NULL); - } - else - { - /* This can handle any delta. This takes - 4+DWARF2_ADDR_SIZE bytes. */ - dw2_asm_output_data (1, 0, "DW_LNE_set_address"); - dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); - dw2_asm_output_data (1, DW_LNE_set_address, NULL); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL); - } - - strcpy (prev_line_label, line_label); - - /* Emit debug info for the source file of the current line, if - different from the previous line. */ - if (line_info->dw_file_num != current_file) - { - current_file = line_info->dw_file_num; - dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file"); - dw2_asm_output_data_uleb128 (current_file, "%lu", current_file); - } - - /* Emit debug info for the current line number, choosing the encoding - that uses the least amount of space. */ - if (line_info->dw_line_num != current_line) - { - line_offset = line_info->dw_line_num - current_line; - line_delta = line_offset - DWARF_LINE_BASE; - current_line = line_info->dw_line_num; - if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) - /* This can handle deltas from -10 to 234, using the current - definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. This - takes 1 byte. */ - dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta, - "line %lu", current_line); - else - { - /* This can handle any delta. This takes at least 4 bytes, - depending on the value being encoded. */ - dw2_asm_output_data (1, DW_LNS_advance_line, - "advance to line %lu", current_line); - dw2_asm_output_data_sleb128 (line_offset, NULL); - dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy"); - } - } - else - /* We still need to start a new row, so output a copy insn. */ - dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy"); - } - - /* Emit debug info for the address of the end of the function. */ - if (0) - { - dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, - "DW_LNS_fixed_advance_pc"); - dw2_asm_output_delta (2, text_end_label, prev_line_label, NULL); - } - else - { - dw2_asm_output_data (1, 0, "DW_LNE_set_address"); - dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); - dw2_asm_output_data (1, DW_LNE_set_address, NULL); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_end_label, NULL); - } - - dw2_asm_output_data (1, 0, "DW_LNE_end_sequence"); - dw2_asm_output_data_uleb128 (1, NULL); - dw2_asm_output_data (1, DW_LNE_end_sequence, NULL); + if (text_section_line_info && text_section_line_info->in_use) + output_one_line_info_table (text_section_line_info); + if (cold_text_section_line_info && cold_text_section_line_info->in_use) + output_one_line_info_table (cold_text_section_line_info); - function = 0; - current_file = 1; - current_line = 1; - for (lt_index = 0; lt_index < separate_line_info_table_in_use;) + if (separate_line_info) { - dw_separate_line_info_ref line_info - = &separate_line_info_table[lt_index]; - -#if 0 - /* Don't emit anything for redundant notes. */ - if (line_info->dw_line_num == current_line - && line_info->dw_file_num == current_file - && line_info->function == function) - goto cont; -#endif - - /* Emit debug info for the address of the current line. If this is - a new function, or the first line of a function, then we need - to handle it differently. */ - ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL, - lt_index); - if (function != line_info->function) - { - function = line_info->function; - - /* Set the address register to the first line in the function. */ - dw2_asm_output_data (1, 0, "DW_LNE_set_address"); - dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); - dw2_asm_output_data (1, DW_LNE_set_address, NULL); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL); - } - else - { - /* ??? See the DW_LNS_advance_pc comment above. */ - if (0) - { - dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, - "DW_LNS_fixed_advance_pc"); - dw2_asm_output_delta (2, line_label, prev_line_label, NULL); - } - else - { - dw2_asm_output_data (1, 0, "DW_LNE_set_address"); - dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); - dw2_asm_output_data (1, DW_LNE_set_address, NULL); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL); - } - } - - strcpy (prev_line_label, line_label); - - /* Emit debug info for the source file of the current line, if - different from the previous line. */ - if (line_info->dw_file_num != current_file) - { - current_file = line_info->dw_file_num; - dw2_asm_output_data (1, DW_LNS_set_file, "DW_LNS_set_file"); - dw2_asm_output_data_uleb128 (current_file, "%lu", current_file); - } - - /* Emit debug info for the current line number, choosing the encoding - that uses the least amount of space. */ - if (line_info->dw_line_num != current_line) - { - line_offset = line_info->dw_line_num - current_line; - line_delta = line_offset - DWARF_LINE_BASE; - current_line = line_info->dw_line_num; - if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1)) - dw2_asm_output_data (1, DWARF_LINE_OPCODE_BASE + line_delta, - "line %lu", current_line); - else - { - dw2_asm_output_data (1, DW_LNS_advance_line, - "advance to line %lu", current_line); - dw2_asm_output_data_sleb128 (line_offset, NULL); - dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy"); - } - } - else - dw2_asm_output_data (1, DW_LNS_copy, "DW_LNS_copy"); - -#if 0 - cont: -#endif - - lt_index++; - - /* If we're done with a function, end its sequence. */ - if (lt_index == separate_line_info_table_in_use - || separate_line_info_table[lt_index].function != function) - { - current_file = 1; - current_line = 1; - - /* Emit debug info for the address of the end of the function. */ - ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function); - if (0) - { - dw2_asm_output_data (1, DW_LNS_fixed_advance_pc, - "DW_LNS_fixed_advance_pc"); - dw2_asm_output_delta (2, line_label, prev_line_label, NULL); - } - else - { - dw2_asm_output_data (1, 0, "DW_LNE_set_address"); - dw2_asm_output_data_uleb128 (1 + DWARF2_ADDR_SIZE, NULL); - dw2_asm_output_data (1, DW_LNE_set_address, NULL); - dw2_asm_output_addr (DWARF2_ADDR_SIZE, line_label, NULL); - } + dw_line_info_table *table; + size_t i; - /* Output the marker for the end of this sequence. */ - dw2_asm_output_data (1, 0, "DW_LNE_end_sequence"); - dw2_asm_output_data_uleb128 (1, NULL); - dw2_asm_output_data (1, DW_LNE_end_sequence, NULL); - } + FOR_EACH_VEC_ELT (dw_line_info_table_p, separate_line_info, i, table) + if (table->in_use) + output_one_line_info_table (table); } /* Output the marker for the end of the line number info. */ ASM_OUTPUT_LABEL (asm_out_file, l2); } - -/* Return the size of the .debug_dcall table for the compilation unit. */ - -static unsigned long -size_of_dcall_table (void) -{ - unsigned long size; - unsigned int i; - dcall_entry *p; - tree last_poc_decl = NULL; - - /* Header: version + debug info section pointer + pointer size. */ - size = 2 + DWARF_OFFSET_SIZE + 1; - - /* Each entry: code label + DIE offset. */ - FOR_EACH_VEC_ELT (dcall_entry, dcall_table, i, p) - { - gcc_assert (p->targ_die != NULL); - /* Insert a "from" entry when the point-of-call DIE offset changes. */ - if (p->poc_decl != last_poc_decl) - { - dw_die_ref poc_die = lookup_decl_die (p->poc_decl); - gcc_assert (poc_die); - last_poc_decl = p->poc_decl; - if (poc_die) - size += (DWARF_OFFSET_SIZE - + size_of_uleb128 (poc_die->die_offset)); - } - size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->targ_die->die_offset); - } - - return size; -} - -/* Output the direct call table used to disambiguate PC values when - identical function have been merged. */ - -static void -output_dcall_table (void) -{ - unsigned i; - unsigned long dcall_length = size_of_dcall_table (); - dcall_entry *p; - char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; - tree last_poc_decl = NULL; - - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) - dw2_asm_output_data (4, 0xffffffff, - "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, dcall_length, - "Length of Direct Call Table"); - dw2_asm_output_data (2, 4, "Version number"); - dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, - debug_info_section, - "Offset of Compilation Unit Info"); - dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); - - FOR_EACH_VEC_ELT (dcall_entry, dcall_table, i, p) - { - /* Insert a "from" entry when the point-of-call DIE offset changes. */ - if (p->poc_decl != last_poc_decl) - { - dw_die_ref poc_die = lookup_decl_die (p->poc_decl); - last_poc_decl = p->poc_decl; - if (poc_die) - { - dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "New caller"); - dw2_asm_output_data_uleb128 (poc_die->die_offset, - "Caller DIE offset"); - } - } - ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); - dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); - dw2_asm_output_data_uleb128 (p->targ_die->die_offset, - "Callee DIE offset"); - } -} - -/* Return the size of the .debug_vcall table for the compilation unit. */ - -static unsigned long -size_of_vcall_table (void) -{ - unsigned long size; - unsigned int i; - vcall_entry *p; - - /* Header: version + pointer size. */ - size = 2 + 1; - - /* Each entry: code label + vtable slot index. */ - FOR_EACH_VEC_ELT (vcall_entry, vcall_table, i, p) - size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->vtable_slot); - - return size; -} - -/* Output the virtual call table used to disambiguate PC values when - identical function have been merged. */ - -static void -output_vcall_table (void) -{ - unsigned i; - unsigned long vcall_length = size_of_vcall_table (); - vcall_entry *p; - char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; - - if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) - dw2_asm_output_data (4, 0xffffffff, - "Initial length escape value indicating 64-bit DWARF extension"); - dw2_asm_output_data (DWARF_OFFSET_SIZE, vcall_length, - "Length of Virtual Call Table"); - dw2_asm_output_data (2, 4, "Version number"); - dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); - - FOR_EACH_VEC_ELT (vcall_entry, vcall_table, i, p) - { - ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); - dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); - dw2_asm_output_data_uleb128 (p->vtable_slot, "Vtable slot"); - } -} /* Given a pointer to a tree node for some base type, return a pointer to a DIE that describes the given type. @@ -12881,7 +12779,12 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, /* Else cv-qualified version of named type; fall through. */ } - if (is_const_type) + if (is_const_type + /* If both is_const_type and is_volatile_type, prefer the path + which leads to a qualified type. */ + && (!is_volatile_type + || get_qualified_type (type, TYPE_QUAL_CONST) == NULL_TREE + || get_qualified_type (type, TYPE_QUAL_VOLATILE) != NULL_TREE)) { mod_type_die = new_die (DW_TAG_const_type, comp_unit_die (), type); sub_die = modified_type_die (type, 0, is_volatile_type, context_die); @@ -12889,7 +12792,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, else if (is_volatile_type) { mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die (), type); - sub_die = modified_type_die (type, 0, 0, context_die); + sub_die = modified_type_die (type, is_const_type, 0, context_die); } else if (code == POINTER_TYPE) { @@ -12903,7 +12806,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, } else if (code == REFERENCE_TYPE) { - if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4) + if (TYPE_REF_IS_RVALUE (type) && use_debug_types) mod_type_die = new_die (DW_TAG_rvalue_reference_type, comp_unit_die (), type); else @@ -12961,6 +12864,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, useful source coordinates anyway. */ name = DECL_NAME (name); add_name_attribute (mod_type_die, IDENTIFIER_POINTER (name)); + add_gnat_descriptive_type_attribute (mod_type_die, type, context_die); } /* This probably indicates a bug. */ else if (mod_type_die && mod_type_die->die_tag == DW_TAG_base_type) @@ -13596,9 +13500,16 @@ const_ok_for_output_1 (rtx *rtlp, void *data ATTRIBUTE_UNUSED) inform (current_function_decl ? DECL_SOURCE_LOCATION (current_function_decl) : UNKNOWN_LOCATION, +#if NUM_UNSPEC_VALUES > 0 + "non-delegitimized UNSPEC %s (%d) found in variable location", + ((XINT (rtl, 1) >= 0 && XINT (rtl, 1) < NUM_UNSPEC_VALUES) + ? unspec_strings[XINT (rtl, 1)] : "unknown"), + XINT (rtl, 1)); +#else "non-delegitimized UNSPEC %d found in variable location", XINT (rtl, 1)); #endif +#endif expansion_failed (NULL_TREE, rtl, "UNSPEC hasn't been delegitimized.\n"); return 1; @@ -13795,9 +13706,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, break; case LO_SUM: - rtl = XEXP (rtl, 1); - - /* ... fall through ... */ + return mem_loc_descriptor (XEXP (rtl, 1), mode, initialized); case LABEL_REF: /* Some ports can transform a symbol ref into a label ref, because @@ -13847,6 +13756,28 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, "CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor"); return 0; + case ENTRY_VALUE: + if (dwarf_strict) + return NULL; + mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0); + mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc; + if (REG_P (ENTRY_VALUE_EXP (rtl))) + mem_loc_result->dw_loc_oprnd1.v.val_loc + = one_reg_loc_descriptor (dbx_reg_number (ENTRY_VALUE_EXP (rtl)), + VAR_INIT_STATUS_INITIALIZED); + else if (MEM_P (ENTRY_VALUE_EXP (rtl)) && REG_P (XEXP (ENTRY_VALUE_EXP (rtl), 0))) + { + dw_loc_descr_ref ref + = mem_loc_descriptor (ENTRY_VALUE_EXP (rtl), GET_MODE (rtl), + VAR_INIT_STATUS_INITIALIZED); + if (ref == NULL || ref->dw_loc_opc == DW_OP_fbreg) + return NULL; + mem_loc_result->dw_loc_oprnd1.v.val_loc = ref; + } + else + gcc_unreachable (); + return mem_loc_result; + case PRE_MODIFY: /* Extract the PLUS expression nested inside and fall into PLUS code below. */ @@ -14262,8 +14193,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, && ((unsigned) INTVAL (XEXP (rtl, 1)) + (unsigned) INTVAL (XEXP (rtl, 2)) <= GET_MODE_BITSIZE (GET_MODE (rtl))) - && GET_MODE_BITSIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE - && GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE) + && GET_MODE_SIZE (GET_MODE (rtl)) <= DWARF2_ADDR_SIZE + && GET_MODE_SIZE (GET_MODE (XEXP (rtl, 0))) <= DWARF2_ADDR_SIZE) { int shift, size; op0 = mem_loc_descriptor (XEXP (rtl, 0), mode, @@ -15080,9 +15011,23 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) } if (descr) { + bool range_across_switch = false; + /* If section switch happens in between node->label + and node->next->label (or end of function) and + we can't emit it as a single entry list, + emit two ranges, first one ending at the end + of first partition and second one starting at the + beginning of second partition. */ + if (node == loc_list->last_before_switch + && (node != loc_list->first || loc_list->first->next) + && current_function_decl) + { + endname = current_fde ()->dw_fde_end; + range_across_switch = true; + } /* The variable has a location between NODE->LABEL and NODE->NEXT->LABEL. */ - if (node->next) + else if (node->next) endname = node->next->label; /* If the variable has a location at the last label it keeps its location until the end of function. */ @@ -15097,6 +15042,30 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) *listp = new_loc_list (descr, node->label, endname, secname); listp = &(*listp)->dw_loc_next; + + if (range_across_switch) + { + if (GET_CODE (node->loc) == EXPR_LIST) + descr = dw_sra_loc_expr (decl, node->loc); + else + { + initialized = NOTE_VAR_LOCATION_STATUS (node->loc); + varloc = NOTE_VAR_LOCATION (node->loc); + descr = dw_loc_list_1 (decl, varloc, want_address, + initialized); + } + gcc_assert (descr); + /* The variable has a location between NODE->LABEL and + NODE->NEXT->LABEL. */ + if (node->next) + endname = node->next->label; + else + endname = current_fde ()->dw_fde_second_end; + *listp = new_loc_list (descr, + current_fde ()->dw_fde_second_begin, + endname, secname); + listp = &(*listp)->dw_loc_next; + } } } @@ -15415,12 +15384,12 @@ loc_list_from_tree (tree loc, int want_address) /* FALLTHRU */ case PARM_DECL: + case RESULT_DECL: if (DECL_HAS_VALUE_EXPR_P (loc)) return loc_list_from_tree (DECL_VALUE_EXPR (loc), want_address); /* FALLTHRU */ - case RESULT_DECL: case FUNCTION_DECL: { rtx rtl; @@ -16495,6 +16464,8 @@ rtl_for_decl_init (tree init, tree type) { rtx rtl = NULL_RTX; + STRIP_NOPS (init); + /* If a variable is initialized with a string constant without embedded zeros, build CONST_STRING. */ if (TREE_CODE (init) == STRING_CST && TREE_CODE (type) == ARRAY_TYPE) @@ -16519,7 +16490,10 @@ rtl_for_decl_init (tree init, tree type) } /* Other aggregates, and complex values, could be represented using CONCAT: FIXME! */ - else if (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE) + else if (AGGREGATE_TYPE_P (type) + || (TREE_CODE (init) == VIEW_CONVERT_EXPR + && AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (init, 0)))) + || TREE_CODE (type) == COMPLEX_TYPE) ; /* Vectors only work if their mode is supported by the target. FIXME: generic vectors ought to work too. */ @@ -16678,7 +16652,13 @@ rtl_for_decl_location (tree decl) } else if (TREE_CODE (decl) == PARM_DECL) { - if (rtl == NULL_RTX || is_pseudo_reg (rtl)) + if (rtl == NULL_RTX + || is_pseudo_reg (rtl) + || (MEM_P (rtl) + && is_pseudo_reg (XEXP (rtl, 0)) + && DECL_INCOMING_RTL (decl) + && MEM_P (DECL_INCOMING_RTL (decl)) + && GET_MODE (rtl) == GET_MODE (DECL_INCOMING_RTL (decl)))) { tree declared_type = TREE_TYPE (decl); tree passed_type = DECL_ARG_TYPE (decl); @@ -16690,7 +16670,8 @@ rtl_for_decl_location (tree decl) all cases where (rtl == NULL_RTX) just below. */ if (dmode == pmode) rtl = DECL_INCOMING_RTL (decl); - else if (SCALAR_INT_MODE_P (dmode) + else if ((rtl == NULL_RTX || is_pseudo_reg (rtl)) + && SCALAR_INT_MODE_P (dmode) && GET_MODE_SIZE (dmode) <= GET_MODE_SIZE (pmode) && DECL_INCOMING_RTL (decl)) { @@ -16856,15 +16837,22 @@ fortran_common (tree decl, HOST_WIDE_INT *value) these things can crop up in other ways also.) Note that one type of constant value which can be passed into an inlined function is a constant pointer. This can happen for example if an actual argument in an inlined - function call evaluates to a compile-time constant address. */ + function call evaluates to a compile-time constant address. + + CACHE_P is true if it is worth caching the location list for DECL, + so that future calls can reuse it rather than regenerate it from scratch. + This is true for BLOCK_NONLOCALIZED_VARS in inlined subroutines, + since we will need to refer to them each time the function is inlined. */ static bool -add_location_or_const_value_attribute (dw_die_ref die, tree decl, +add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p, enum dwarf_attribute attr) { rtx rtl; dw_loc_list_ref list; var_loc_list *loc_list; + cached_dw_loc_list *cache; + void **slot; if (TREE_CODE (decl) == ERROR_MARK) return false; @@ -16901,7 +16889,33 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, && add_const_value_attribute (die, rtl)) return true; } - list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2); + /* If this decl is from BLOCK_NONLOCALIZED_VARS, we might need its + list several times. See if we've already cached the contents. */ + list = NULL; + if (loc_list == NULL || cached_dw_loc_list_table == NULL) + cache_p = false; + if (cache_p) + { + cache = (cached_dw_loc_list *) + htab_find_with_hash (cached_dw_loc_list_table, decl, DECL_UID (decl)); + if (cache) + list = cache->loc_list; + } + if (list == NULL) + { + list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2); + /* It is usually worth caching this result if the decl is from + BLOCK_NONLOCALIZED_VARS and if the list has at least two elements. */ + if (cache_p && list && list->dw_loc_next) + { + slot = htab_find_slot_with_hash (cached_dw_loc_list_table, decl, + DECL_UID (decl), INSERT); + cache = ggc_alloc_cleared_cached_dw_loc_list (); + cache->decl_id = DECL_UID (decl); + cache->loc_list = list; + *slot = cache; + } + } if (list) { add_AT_location_description (die, attr, list); @@ -17170,33 +17184,61 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) last_cfa = next_cfa; last_label = start_label; - for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) - switch (cfi->dw_cfi_opc) - { - case DW_CFA_set_loc: - case DW_CFA_advance_loc1: - case DW_CFA_advance_loc2: - case DW_CFA_advance_loc4: - if (!cfa_equal_p (&last_cfa, &next_cfa)) - { - *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), - start_label, last_label, section); - - list_tail = &(*list_tail)->dw_loc_next; - last_cfa = next_cfa; - start_label = last_label; - } - last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; - break; - - case DW_CFA_advance_loc: - /* The encoding is complex enough that we should never emit this. */ - gcc_unreachable (); + if (fde->dw_fde_second_begin && fde->dw_fde_switch_cfi == NULL) + { + /* If the first partition contained no CFI adjustments, the + CIE opcodes apply to the whole first partition. */ + *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), + fde->dw_fde_begin, fde->dw_fde_end, section); + list_tail =&(*list_tail)->dw_loc_next; + start_label = last_label = fde->dw_fde_second_begin; + } - default: - lookup_cfa_1 (cfi, &next_cfa, &remember); - break; - } + for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) + { + switch (cfi->dw_cfi_opc) + { + case DW_CFA_set_loc: + case DW_CFA_advance_loc1: + case DW_CFA_advance_loc2: + case DW_CFA_advance_loc4: + if (!cfa_equal_p (&last_cfa, &next_cfa)) + { + *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), + start_label, last_label, section); + + list_tail = &(*list_tail)->dw_loc_next; + last_cfa = next_cfa; + start_label = last_label; + } + last_label = cfi->dw_cfi_oprnd1.dw_cfi_addr; + break; + + case DW_CFA_advance_loc: + /* The encoding is complex enough that we should never emit this. */ + gcc_unreachable (); + + default: + lookup_cfa_1 (cfi, &next_cfa, &remember); + break; + } + if (cfi == fde->dw_fde_switch_cfi) + { + if (!cfa_equal_p (&last_cfa, &next_cfa)) + { + *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), + start_label, last_label, section); + + list_tail = &(*list_tail)->dw_loc_next; + last_cfa = next_cfa; + start_label = last_label; + } + *list_tail = new_loc_list (build_cfa_loc (&last_cfa, offset), + start_label, fde->dw_fde_end, section); + list_tail = &(*list_tail)->dw_loc_next; + start_label = last_label = fde->dw_fde_second_begin; + } + } if (!cfa_equal_p (&last_cfa, &next_cfa)) { @@ -17207,7 +17249,10 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) } *list_tail = new_loc_list (build_cfa_loc (&next_cfa, offset), - start_label, fde->dw_fde_end, section); + start_label, + fde->dw_fde_second_begin + ? fde->dw_fde_second_end : fde->dw_fde_end, + section); if (list && list->dw_loc_next) gen_llsym (list); @@ -17265,6 +17310,38 @@ add_name_attribute (dw_die_ref die, const char *name_string) } } +/* Retrieve the descriptive type of TYPE, if any, make sure it has a + DIE and attach a DW_AT_GNAT_descriptive_type attribute to the DIE + of TYPE accordingly. + + ??? This is a temporary measure until after we're able to generate + regular DWARF for the complex Ada type system. */ + +static void +add_gnat_descriptive_type_attribute (dw_die_ref die, tree type, + dw_die_ref context_die) +{ + tree dtype; + dw_die_ref dtype_die; + + if (!lang_hooks.types.descriptive_type) + return; + + dtype = lang_hooks.types.descriptive_type (type); + if (!dtype) + return; + + dtype_die = lookup_type_die (dtype); + if (!dtype_die) + { + gen_type_die (dtype, context_die); + dtype_die = lookup_type_die (dtype); + gcc_assert (dtype_die); + } + + add_AT_die_ref (die, DW_AT_GNAT_descriptive_type, dtype_die); +} + /* Generate a DW_AT_comp_dir attribute for DIE. */ static void @@ -17563,7 +17640,7 @@ add_bit_offset_attribute (dw_die_ref die, tree decl) HOST_WIDE_INT bitpos_int; HOST_WIDE_INT highest_order_object_bit_offset; HOST_WIDE_INT highest_order_field_bit_offset; - HOST_WIDE_INT unsigned bit_offset; + HOST_WIDE_INT bit_offset; /* Must be a field and a bit field. */ gcc_assert (type && TREE_CODE (decl) == FIELD_DECL); @@ -17596,7 +17673,10 @@ add_bit_offset_attribute (dw_die_ref die, tree decl) ? highest_order_object_bit_offset - highest_order_field_bit_offset : highest_order_field_bit_offset - highest_order_object_bit_offset); - add_AT_unsigned (die, DW_AT_bit_offset, bit_offset); + if (bit_offset < 0) + add_AT_int (die, DW_AT_bit_offset, bit_offset); + else + add_AT_unsigned (die, DW_AT_bit_offset, (unsigned HOST_WIDE_INT) bit_offset); } /* For a FIELD_DECL node which represents a bit field, output an attribute @@ -17620,7 +17700,7 @@ static inline void add_prototyped_attribute (dw_die_ref die, tree func_type) { if (get_AT_unsigned (comp_unit_die (), DW_AT_language) == DW_LANG_C89 - && TYPE_ARG_TYPES (func_type) != NULL) + && prototype_p (func_type)) add_AT_flag (die, DW_AT_prototyped, 1); } @@ -17717,8 +17797,11 @@ add_linkage_attr (dw_die_ref die, tree decl) static void add_src_coords_attributes (dw_die_ref die, tree decl) { - expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl)); + expanded_location s; + if (DECL_SOURCE_LOCATION (decl) == UNKNOWN_LOCATION) + return; + s = expand_location (DECL_SOURCE_LOCATION (decl)); add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file)); add_AT_unsigned (die, DW_AT_decl_line, s.line); } @@ -17887,7 +17970,7 @@ scope_die_for (tree t, dw_die_ref context_die) scope_die = comp_unit_die (); } else - scope_die = lookup_type_die (containing_scope); + scope_die = lookup_type_die_strip_naming_typedef (containing_scope); } else scope_die = context_die; @@ -18138,6 +18221,7 @@ gen_array_type_die (tree type, dw_die_ref context_die) array_die = new_die (DW_TAG_array_type, scope_die, type); add_name_attribute (array_die, type_tag (type)); + add_gnat_descriptive_type_attribute (array_die, type, context_die); equate_type_number_to_die (type, array_die); if (TREE_CODE (type) == VECTOR_TYPE) @@ -18440,6 +18524,7 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die) scope_die_for (type, context_die), type); equate_type_number_to_die (type, type_die); add_name_attribute (type_die, type_tag (type)); + add_gnat_descriptive_type_attribute (type_die, type, context_die); if (dwarf_version >= 4 || !dwarf_strict) { if (ENUM_IS_SCOPED (type)) @@ -18562,7 +18647,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p, equate_decl_number_to_die (node, parm_die); if (! DECL_ABSTRACT (node_or_origin)) add_location_or_const_value_attribute (parm_die, node_or_origin, - DW_AT_location); + node == NULL, DW_AT_location); break; @@ -18714,7 +18799,7 @@ gen_type_die_for_member (tree type, tree member, dw_die_ref context_die) gcc_assert (!decl_ultimate_origin (member)); push_decl_scope (type); - type_die = lookup_type_die (type); + type_die = lookup_type_die_strip_naming_typedef (type); if (TREE_CODE (member) == FUNCTION_DECL) gen_subprogram_die (member, type_die); else if (TREE_CODE (member) == FIELD_DECL) @@ -18747,6 +18832,9 @@ dwarf2out_abstract_function (tree decl) tree context; int was_abstract; htab_t old_decl_loc_table; + htab_t old_cached_dw_loc_list_table; + int old_call_site_count, old_tail_call_site_count; + struct call_arg_loc_node *old_call_arg_locations; /* Make sure we have the actual abstract inline, not a clone. */ decl = DECL_ORIGIN (decl); @@ -18761,6 +18849,14 @@ dwarf2out_abstract_function (tree decl) get locations in abstract instantces. */ old_decl_loc_table = decl_loc_table; decl_loc_table = NULL; + old_cached_dw_loc_list_table = cached_dw_loc_list_table; + cached_dw_loc_list_table = NULL; + old_call_arg_locations = call_arg_locations; + call_arg_locations = NULL; + old_call_site_count = call_site_count; + call_site_count = -1; + old_tail_call_site_count = tail_call_site_count; + tail_call_site_count = -1; /* Be sure we've emitted the in-class declaration DIE (if any) first, so we don't get confused by DECL_ABSTRACT. */ @@ -18785,6 +18881,10 @@ dwarf2out_abstract_function (tree decl) current_function_decl = save_fn; decl_loc_table = old_decl_loc_table; + cached_dw_loc_list_table = old_cached_dw_loc_list_table; + call_arg_locations = old_call_arg_locations; + call_site_count = old_call_site_count; + tail_call_site_count = old_tail_call_site_count; pop_cfun (); } @@ -18860,16 +18960,51 @@ premark_types_used_by_global_vars (void) premark_types_used_by_global_vars_helper, NULL); } +/* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE + for CA_LOC call arg loc node. */ + +static dw_die_ref +gen_call_site_die (tree decl, dw_die_ref subr_die, + struct call_arg_loc_node *ca_loc) +{ + dw_die_ref stmt_die = NULL, die; + tree block = ca_loc->block; + + while (block + && block != DECL_INITIAL (decl) + && TREE_CODE (block) == BLOCK) + { + if (VEC_length (dw_die_ref, block_map) > BLOCK_NUMBER (block)) + stmt_die = VEC_index (dw_die_ref, block_map, BLOCK_NUMBER (block)); + if (stmt_die) + break; + block = BLOCK_SUPERCONTEXT (block); + } + if (stmt_die == NULL) + stmt_die = subr_die; + die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE); + add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label); + if (ca_loc->tail_call_p) + add_AT_flag (die, DW_AT_GNU_tail_call, 1); + if (ca_loc->symbol_ref) + { + dw_die_ref tdie = lookup_decl_die (SYMBOL_REF_DECL (ca_loc->symbol_ref)); + if (tdie) + add_AT_die_ref (die, DW_AT_abstract_origin, tdie); + else + add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref); + } + return die; +} + /* Generate a DIE to represent a declared function (either file-scope or block-local). */ static void gen_subprogram_die (tree decl, dw_die_ref context_die) { - char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; tree origin = decl_ultimate_origin (decl); dw_die_ref subr_die; - tree fn_arg_types; tree outer_scope; dw_die_ref old_die = lookup_decl_die (decl); int declaration = (current_function_decl != decl @@ -19036,12 +19171,24 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) if (!flag_reorder_blocks_and_partition) { - ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, - current_function_funcdef_no); - add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); - ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, - current_function_funcdef_no); - add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); + dw_fde_ref fde = &fde_table[current_funcdef_fde]; + if (fde->dw_fde_begin) + { + /* We have already generated the labels. */ + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); + } + else + { + /* Create start/end labels and add the range. */ + char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL, + current_function_funcdef_no); + add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id); + ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL, + current_function_funcdef_no); + add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id); + } #if VMS_DEBUGGING_INFO /* HP OpenVMS Industry Standard 64: DWARF Extensions @@ -19057,8 +19204,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) attributes allow a compiler to communicate the location(s) to use. */ { - dw_fde_ref fde = &fde_table[current_funcdef_fde]; - if (fde->dw_fde_vms_end_prologue) add_AT_vms_delta (subr_die, DW_AT_HP_prologue, fde->dw_fde_begin, fde->dw_fde_vms_end_prologue); @@ -19070,22 +19215,87 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) #endif add_pubname (decl, subr_die); - add_arange (decl, subr_die); } else - { /* Do nothing for now; maybe need to duplicate die, one for - hot section and one for cold section, then use the hot/cold - section begin/end labels to generate the aranges... */ - /* - add_AT_lbl_id (subr_die, DW_AT_low_pc, hot_section_label); - add_AT_lbl_id (subr_die, DW_AT_high_pc, hot_section_end_label); - add_AT_lbl_id (subr_die, DW_AT_lo_user, unlikely_section_label); - add_AT_lbl_id (subr_die, DW_AT_hi_user, cold_section_end_label); - - add_pubname (decl, subr_die); - add_arange (decl, subr_die); - add_arange (decl, subr_die); - */ + { /* Generate pubnames entries for the split function code + ranges. */ + dw_fde_ref fde = &fde_table[current_funcdef_fde]; + + if (fde->dw_fde_second_begin) + { + if (dwarf_version >= 3 || !dwarf_strict) + { + /* We should use ranges for non-contiguous code section + addresses. Use the actual code range for the initial + section, since the HOT/COLD labels might precede an + alignment offset. */ + bool range_list_added = false; + add_ranges_by_labels (subr_die, fde->dw_fde_begin, + fde->dw_fde_end, &range_list_added); + add_ranges_by_labels (subr_die, fde->dw_fde_second_begin, + fde->dw_fde_second_end, + &range_list_added); + add_pubname (decl, subr_die); + if (range_list_added) + add_ranges (NULL); + } + else + { + /* There is no real support in DW2 for this .. so we make + a work-around. First, emit the pub name for the segment + containing the function label. Then make and emit a + simplified subprogram DIE for the second segment with the + name pre-fixed by __hot/cold_sect_of_. We use the same + linkage name for the second die so that gdb will find both + sections when given "b foo". */ + const char *name = NULL; + tree decl_name = DECL_NAME (decl); + dw_die_ref seg_die; + + /* Do the 'primary' section. */ + add_AT_lbl_id (subr_die, DW_AT_low_pc, + fde->dw_fde_begin); + add_AT_lbl_id (subr_die, DW_AT_high_pc, + fde->dw_fde_end); + /* Add it. */ + add_pubname (decl, subr_die); + + /* Build a minimal DIE for the secondary section. */ + seg_die = new_die (DW_TAG_subprogram, + subr_die->die_parent, decl); + + if (TREE_PUBLIC (decl)) + add_AT_flag (seg_die, DW_AT_external, 1); + + if (decl_name != NULL + && IDENTIFIER_POINTER (decl_name) != NULL) + { + name = dwarf2_name (decl, 1); + if (! DECL_ARTIFICIAL (decl)) + add_src_coords_attributes (seg_die, decl); + + add_linkage_name (seg_die, decl); + } + gcc_assert (name != NULL); + add_pure_or_virtual_attribute (seg_die, decl); + if (DECL_ARTIFICIAL (decl)) + add_AT_flag (seg_die, DW_AT_artificial, 1); + + name = concat ("__second_sect_of_", name, NULL); + add_AT_lbl_id (seg_die, DW_AT_low_pc, + fde->dw_fde_second_begin); + add_AT_lbl_id (seg_die, DW_AT_high_pc, + fde->dw_fde_second_end); + add_name_attribute (seg_die, name); + add_pubname_string (name, seg_die); + } + } + else + { + add_AT_lbl_id (subr_die, DW_AT_low_pc, fde->dw_fde_begin); + add_AT_lbl_id (subr_die, DW_AT_high_pc, fde->dw_fde_end); + add_pubname (decl, subr_die); + } } #ifdef MIPS_DEBUGGING_INFO @@ -19207,8 +19417,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) void_type_node 2) an unprototyped function declaration (not a definition). This just means that we have no info about the parameters at all. */ - fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); - if (fn_arg_types != NULL) + if (prototype_p (TREE_TYPE (decl))) { /* This is the prototyped case, check for.... */ if (stdarg_p (TREE_TYPE (decl))) @@ -19238,12 +19447,135 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) constructor function. */ if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK) { + int call_site_note_count = 0; + int tail_call_site_note_count = 0; + /* Emit a DW_TAG_variable DIE for a named return value. */ if (DECL_NAME (DECL_RESULT (decl))) gen_decl_die (DECL_RESULT (decl), NULL, subr_die); current_function_has_inlines = 0; decls_for_scope (outer_scope, subr_die, 0); + + if (call_arg_locations && !dwarf_strict) + { + struct call_arg_loc_node *ca_loc; + for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next) + { + dw_die_ref die = NULL; + rtx tloc = NULL_RTX, tlocc = NULL_RTX; + rtx arg, next_arg; + + for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note); + arg; arg = next_arg) + { + dw_loc_descr_ref reg, val; + enum machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1)); + dw_die_ref cdie; + + next_arg = XEXP (arg, 1); + if (REG_P (XEXP (XEXP (arg, 0), 0)) + && next_arg + && MEM_P (XEXP (XEXP (next_arg, 0), 0)) + && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)) + && REGNO (XEXP (XEXP (arg, 0), 0)) + == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))) + next_arg = XEXP (next_arg, 1); + if (mode == VOIDmode) + { + mode = GET_MODE (XEXP (XEXP (arg, 0), 0)); + if (mode == VOIDmode) + mode = GET_MODE (XEXP (arg, 0)); + } + if (GET_MODE_CLASS (mode) != MODE_INT + || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE) + continue; + if (XEXP (XEXP (arg, 0), 0) == pc_rtx) + { + gcc_assert (ca_loc->symbol_ref == NULL_RTX); + tloc = XEXP (XEXP (arg, 0), 1); + continue; + } + else if (GET_CODE (XEXP (XEXP (arg, 0), 0)) == CLOBBER + && XEXP (XEXP (XEXP (arg, 0), 0), 0) == pc_rtx) + { + gcc_assert (ca_loc->symbol_ref == NULL_RTX); + tlocc = XEXP (XEXP (arg, 0), 1); + continue; + } + if (REG_P (XEXP (XEXP (arg, 0), 0))) + reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0), + VAR_INIT_STATUS_INITIALIZED); + else if (MEM_P (XEXP (XEXP (arg, 0), 0))) + reg = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 0), + 0), 0), mode, + VAR_INIT_STATUS_INITIALIZED); + else + continue; + if (reg == NULL) + continue; + val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), VOIDmode, + VAR_INIT_STATUS_INITIALIZED); + if (val == NULL) + continue; + if (die == NULL) + die = gen_call_site_die (decl, subr_die, ca_loc); + cdie = new_die (DW_TAG_GNU_call_site_parameter, die, + NULL_TREE); + add_AT_loc (cdie, DW_AT_location, reg); + add_AT_loc (cdie, DW_AT_GNU_call_site_value, val); + if (next_arg != XEXP (arg, 1)) + { + val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1), + 0), 1), VOIDmode, + VAR_INIT_STATUS_INITIALIZED); + if (val != NULL) + add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val); + } + } + if (die == NULL + && (ca_loc->symbol_ref || tloc)) + die = gen_call_site_die (decl, subr_die, ca_loc); + if (die != NULL && (tloc != NULL_RTX || tlocc != NULL_RTX)) + { + dw_loc_descr_ref tval = NULL; + + if (tloc != NULL_RTX) + tval = mem_loc_descriptor (tloc, VOIDmode, + VAR_INIT_STATUS_INITIALIZED); + if (tval) + add_AT_loc (die, DW_AT_GNU_call_site_target, tval); + else if (tlocc != NULL_RTX) + { + tval = mem_loc_descriptor (tlocc, VOIDmode, + VAR_INIT_STATUS_INITIALIZED); + if (tval) + add_AT_loc (die, DW_AT_GNU_call_site_target_clobbered, + tval); + } + } + if (die != NULL) + { + call_site_note_count++; + if (ca_loc->tail_call_p) + tail_call_site_note_count++; + } + } + } + call_arg_locations = NULL; + call_arg_loc_last = NULL; + if (tail_call_site_count >= 0 + && tail_call_site_count == tail_call_site_note_count + && !dwarf_strict) + { + if (call_site_count >= 0 + && call_site_count == call_site_note_count) + add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1); + else + add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1); + } + call_site_count = -1; + tail_call_site_count = -1; } /* Add the calling convention attribute if requested. */ add_calling_convention_attribute (subr_die, decl); @@ -19497,9 +19829,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin))) defer_location (decl_or_origin, var_die); else - add_location_or_const_value_attribute (var_die, - decl_or_origin, - DW_AT_location); + add_location_or_const_value_attribute (var_die, decl_or_origin, + decl == NULL, DW_AT_location); add_pubname (decl_or_origin, var_die); } else @@ -19632,6 +19963,14 @@ gen_lexical_block_die (tree stmt, dw_die_ref context_die, int depth) { dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt); + if (call_arg_locations) + { + if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt)) + VEC_safe_grow_cleared (dw_die_ref, heap, block_map, + BLOCK_NUMBER (stmt) + 1); + VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), stmt_die); + } + if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt)) add_high_low_attributes (stmt, stmt_die); @@ -19662,6 +20001,13 @@ gen_inlined_subroutine_die (tree stmt, dw_die_ref context_die, int depth) dw_die_ref subr_die = new_die (DW_TAG_inlined_subroutine, context_die, stmt); + if (call_arg_locations) + { + if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt)) + VEC_safe_grow_cleared (dw_die_ref, heap, block_map, + BLOCK_NUMBER (stmt) + 1); + VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), subr_die); + } add_abstract_origin_attribute (subr_die, decl); if (TREE_ASM_WRITTEN (stmt)) add_high_low_attributes (stmt, subr_die); @@ -19734,7 +20080,7 @@ gen_reference_type_die (tree type, dw_die_ref context_die) { dw_die_ref ref_die, scope_die = scope_die_for (type, context_die); - if (TYPE_REF_IS_RVALUE (type) && dwarf_version >= 4) + if (TYPE_REF_IS_RVALUE (type) && use_debug_types) ref_die = new_die (DW_TAG_rvalue_reference_type, scope_die, type); else ref_die = new_die (DW_TAG_reference_type, scope_die, type); @@ -19998,7 +20344,10 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die, if (old_die) add_AT_specification (type_die, old_die); else - add_name_attribute (type_die, type_tag (type)); + { + add_name_attribute (type_die, type_tag (type)); + add_gnat_descriptive_type_attribute (type_die, type, context_die); + } } else remove_AT (type_die, DW_AT_declaration); @@ -20006,7 +20355,7 @@ gen_struct_or_union_type_die (tree type, dw_die_ref context_die, /* Generate child dies for template paramaters. */ if (debug_info_level > DINFO_LEVEL_TERSE && COMPLETE_TYPE_P (type)) - gen_generic_params_dies (type); + schedule_generic_params_dies_gen (type); /* If this type has been completed, then give it a byte_size attribute and then give a list of members. */ @@ -20124,6 +20473,14 @@ gen_typedef_die (tree decl, dw_die_ref context_die) anonymous struct DIE. */ if (!TREE_ASM_WRITTEN (type)) gen_tagged_type_die (type, context_die, DINFO_USAGE_DIR_USE); + + /* This is a GNU Extension. We are adding a + DW_AT_linkage_name attribute to the DIE of the + anonymous struct TYPE. The value of that attribute + is the name of the typedef decl naming the anonymous + struct. This greatly eases the work of consumers of + this debug info. */ + add_linkage_attr (lookup_type_die (type), decl); } } @@ -20186,6 +20543,10 @@ gen_tagged_type_die (tree type, out yet, use a NULL context for now; it will be fixed up in decls_for_scope. */ context_die = lookup_decl_die (TYPE_CONTEXT (type)); + /* A declaration DIE doesn't count; nested types need to go in the + specification. */ + if (context_die && is_declaration_die (context_die)) + context_die = NULL; need_pop = 0; } else @@ -20216,13 +20577,23 @@ gen_tagged_type_die (tree type, static void gen_type_die_with_usage (tree type, dw_die_ref context_die, - enum debug_info_usage usage) + enum debug_info_usage usage) { struct array_descr_info info; if (type == NULL_TREE || type == error_mark_node) return; + if (TYPE_NAME (type) != NULL_TREE + && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && is_redundant_typedef (TYPE_NAME (type)) + && DECL_ORIGINAL_TYPE (TYPE_NAME (type))) + /* The DECL of this type is a typedef we don't want to emit debug + info for but we want debug info for its underlying typedef. + This can happen for e.g, the injected-class-name of a C++ + type. */ + type = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); + /* If TYPE is a typedef type variant, let's generate debug info for the parent typedef which TYPE is a type of. */ if (typedef_variant_p (type)) @@ -20590,7 +20961,10 @@ get_context_die (tree context) { /* Find die that represents this context. */ if (TYPE_P (context)) - return force_type_die (TYPE_MAIN_VARIANT (context)); + { + context = TYPE_MAIN_VARIANT (context); + return strip_naming_typedef (context, force_type_die (context)); + } else return force_decl_die (context); } @@ -21259,8 +21633,13 @@ static void dwarf2out_function_decl (tree decl) { dwarf2out_decl (decl); - + call_arg_locations = NULL; + call_arg_loc_last = NULL; + call_site_count = -1; + tail_call_site_count = -1; + VEC_free (dw_die_ref, heap, block_map); htab_empty (decl_loc_table); + htab_empty (cached_dw_loc_list_table); } /* Output a marker (i.e. a label) for the beginning of the generated code for @@ -21320,7 +21699,7 @@ file_table_eq (const void *p1_p, const void *p2_p) const struct dwarf_file_data *const p1 = (const struct dwarf_file_data *) p1_p; const char *const p2 = (const char *) p2_p; - return strcmp (p1->filename, p2) == 0; + return filename_cmp (p1->filename, p2) == 0; } static hashval_t @@ -21351,7 +21730,7 @@ lookup_filename (const char *file_name) call matches this file name. If so, return the index. */ if (file_table_last_lookup && (file_name == file_table_last_lookup->filename - || strcmp (file_table_last_lookup->filename, file_name) == 0)) + || filename_cmp (file_table_last_lookup->filename, file_name) == 0)) return file_table_last_lookup; /* Didn't match the previous lookup, search the table. */ @@ -21419,6 +21798,33 @@ append_entry_to_tmpl_value_parm_die_table (dw_die_ref die, tree arg) &entry); } +/* Return TRUE if T is an instance of generic type, FALSE + otherwise. */ + +static bool +generic_type_p (tree t) +{ + if (t == NULL_TREE || !TYPE_P (t)) + return false; + return lang_hooks.get_innermost_generic_parms (t) != NULL_TREE; +} + +/* Schedule the generation of the generic parameter dies for the + instance of generic type T. The proper generation itself is later + done by gen_scheduled_generic_parms_dies. */ + +static void +schedule_generic_params_dies_gen (tree t) +{ + if (!generic_type_p (t)) + return; + + if (generic_type_instances == NULL) + generic_type_instances = VEC_alloc (tree, gc, 256); + + VEC_safe_push (tree, gc, generic_type_instances, t); +} + /* Add a DW_AT_const_value attribute to DIEs that were scheduled by append_entry_to_tmpl_value_parm_die_table. This function must be called after function DIEs have been generated. */ @@ -21436,6 +21842,24 @@ gen_remaining_tmpl_value_param_die_attribute (void) } } +/* Generate generic parameters DIEs for instances of generic types + that have been previously scheduled by + schedule_generic_params_dies_gen. This function must be called + after all the types of the CU have been laid out. */ + +static void +gen_scheduled_generic_parms_dies (void) +{ + unsigned i; + tree t; + + if (generic_type_instances == NULL) + return; + + FOR_EACH_VEC_ELT (tree, generic_type_instances, i, t) + gen_generic_params_dies (t); +} + /* Replace DW_AT_name for the decl with name. */ @@ -21468,135 +21892,6 @@ dwarf2out_set_name (tree decl, tree name) add_name_attribute (die, dname); } -/* Called by the final INSN scan whenever we see a direct function call. - Make an entry into the direct call table, recording the point of call - and a reference to the target function's debug entry. */ - -static void -dwarf2out_direct_call (tree targ) -{ - dcall_entry e; - tree origin = decl_ultimate_origin (targ); - - /* If this is a clone, use the abstract origin as the target. */ - if (origin) - targ = origin; - - e.poc_label_num = poc_label_num++; - e.poc_decl = current_function_decl; - e.targ_die = force_decl_die (targ); - VEC_safe_push (dcall_entry, gc, dcall_table, &e); - - /* Drop a label at the return point to mark the point of call. */ - ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); -} - -/* Returns a hash value for X (which really is a struct vcall_insn). */ - -static hashval_t -vcall_insn_table_hash (const void *x) -{ - return (hashval_t) ((const struct vcall_insn *) x)->insn_uid; -} - -/* Return nonzero if insn_uid of struct vcall_insn *X is the same as - insnd_uid of *Y. */ - -static int -vcall_insn_table_eq (const void *x, const void *y) -{ - return (((const struct vcall_insn *) x)->insn_uid - == ((const struct vcall_insn *) y)->insn_uid); -} - -/* Associate VTABLE_SLOT with INSN_UID in the VCALL_INSN_TABLE. */ - -static void -store_vcall_insn (unsigned int vtable_slot, int insn_uid) -{ - struct vcall_insn *item = ggc_alloc_vcall_insn (); - struct vcall_insn **slot; - - gcc_assert (item); - item->insn_uid = insn_uid; - item->vtable_slot = vtable_slot; - slot = (struct vcall_insn **) - htab_find_slot_with_hash (vcall_insn_table, &item, - (hashval_t) insn_uid, INSERT); - *slot = item; -} - -/* Return the VTABLE_SLOT associated with INSN_UID. */ - -static unsigned int -lookup_vcall_insn (unsigned int insn_uid) -{ - struct vcall_insn item; - struct vcall_insn *p; - - item.insn_uid = insn_uid; - item.vtable_slot = 0; - p = (struct vcall_insn *) htab_find_with_hash (vcall_insn_table, - (void *) &item, - (hashval_t) insn_uid); - if (p == NULL) - return (unsigned int) -1; - return p->vtable_slot; -} - - -/* Called when lowering indirect calls to RTL. We make a note of INSN_UID - and the OBJ_TYPE_REF_TOKEN from ADDR. For C++ virtual calls, the token - is the vtable slot index that we will need to put in the virtual call - table later. */ - -static void -dwarf2out_virtual_call_token (tree addr, int insn_uid) -{ - if (is_cxx() && TREE_CODE (addr) == OBJ_TYPE_REF) - { - tree token = OBJ_TYPE_REF_TOKEN (addr); - if (TREE_CODE (token) == INTEGER_CST) - store_vcall_insn (TREE_INT_CST_LOW (token), insn_uid); - } -} - -/* Called when scheduling RTL, when a CALL_INSN is split. Copies the - OBJ_TYPE_REF_TOKEN previously associated with OLD_INSN and associates it - with NEW_INSN. */ - -static void -dwarf2out_copy_call_info (rtx old_insn, rtx new_insn) -{ - unsigned int vtable_slot = lookup_vcall_insn (INSN_UID (old_insn)); - - if (vtable_slot != (unsigned int) -1) - store_vcall_insn (vtable_slot, INSN_UID (new_insn)); -} - -/* Called by the final INSN scan whenever we see a virtual function call. - Make an entry into the virtual call table, recording the point of call - and the slot index of the vtable entry used to call the virtual member - function. The slot index was associated with the INSN_UID during the - lowering to RTL. */ - -static void -dwarf2out_virtual_call (int insn_uid) -{ - unsigned int vtable_slot = lookup_vcall_insn (insn_uid); - vcall_entry e; - - if (vtable_slot == (unsigned int) -1) - return; - - e.poc_label_num = poc_label_num++; - e.vtable_slot = vtable_slot; - VEC_safe_push (vcall_entry, gc, vcall_table, &e); - - /* Drop a label at the return point to mark the point of call. */ - ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); -} - /* Called by the final INSN scan whenever we see a var location. We use it to drop labels in the right places, and throw the location in our lookup table. */ @@ -21611,16 +21906,35 @@ dwarf2out_var_location (rtx loc_note) static const char *last_postcall_label; static bool last_in_cold_section_p; tree decl; + bool var_loc_p; + + if (!NOTE_P (loc_note)) + { + if (CALL_P (loc_note)) + { + call_site_count++; + if (SIBLING_CALL_P (loc_note)) + tail_call_site_count++; + } + return; + } - if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note))) + var_loc_p = NOTE_KIND (loc_note) == NOTE_INSN_VAR_LOCATION; + if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note))) return; next_real = next_real_insn (loc_note); + /* If there are no instructions which would be affected by this note, don't do anything. */ - if (next_real == NULL_RTX && !NOTE_DURING_CALL_P (loc_note)) + if (var_loc_p + && next_real == NULL_RTX + && !NOTE_DURING_CALL_P (loc_note)) return; + if (next_real == NULL_RTX) + next_real = get_last_insn (); + /* If there were any real insns between note we processed last time and this note (or if it is the first note), clear last_{,postcall_}label so that they are not reused this time. */ @@ -21632,12 +21946,20 @@ dwarf2out_var_location (rtx loc_note) last_postcall_label = NULL; } - decl = NOTE_VAR_LOCATION_DECL (loc_note); - newloc = add_var_loc_to_decl (decl, loc_note, - NOTE_DURING_CALL_P (loc_note) - ? last_postcall_label : last_label); - if (newloc == NULL) - return; + if (var_loc_p) + { + decl = NOTE_VAR_LOCATION_DECL (loc_note); + newloc = add_var_loc_to_decl (decl, loc_note, + NOTE_DURING_CALL_P (loc_note) + ? last_postcall_label : last_label); + if (newloc == NULL) + return; + } + else + { + decl = NULL_TREE; + newloc = NULL; + } /* If there were no real insns between note we processed last time and this note, use the label we emitted last time. Otherwise @@ -21650,7 +21972,43 @@ dwarf2out_var_location (rtx loc_note) last_label = ggc_strdup (loclabel); } - if (!NOTE_DURING_CALL_P (loc_note)) + if (!var_loc_p) + { + struct call_arg_loc_node *ca_loc + = ggc_alloc_cleared_call_arg_loc_node (); + rtx prev = prev_real_insn (loc_note), x; + ca_loc->call_arg_loc_note = loc_note; + ca_loc->next = NULL; + ca_loc->label = last_label; + gcc_assert (prev + && (CALL_P (prev) + || (NONJUMP_INSN_P (prev) + && GET_CODE (PATTERN (prev)) == SEQUENCE + && CALL_P (XVECEXP (PATTERN (prev), 0, 0))))); + if (!CALL_P (prev)) + prev = XVECEXP (PATTERN (prev), 0, 0); + ca_loc->tail_call_p = SIBLING_CALL_P (prev); + x = PATTERN (prev); + if (GET_CODE (x) == PARALLEL) + x = XVECEXP (x, 0, 0); + if (GET_CODE (x) == SET) + x = SET_SRC (x); + if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0))) + { + x = XEXP (XEXP (x, 0), 0); + if (GET_CODE (x) == SYMBOL_REF + && SYMBOL_REF_DECL (x) + && TREE_CODE (SYMBOL_REF_DECL (x)) == FUNCTION_DECL) + ca_loc->symbol_ref = x; + } + ca_loc->block = insn_scope (prev); + if (call_arg_locations) + call_arg_loc_last->next = ca_loc; + else + call_arg_locations = ca_loc; + call_arg_loc_last = ca_loc; + } + else if (!NOTE_DURING_CALL_P (loc_note)) newloc->label = last_label; else { @@ -21666,6 +22024,99 @@ dwarf2out_var_location (rtx loc_note) last_in_cold_section_p = in_cold_section_p; } +/* Note in one location list that text section has changed. */ + +static int +var_location_switch_text_section_1 (void **slot, void *data ATTRIBUTE_UNUSED) +{ + var_loc_list *list = (var_loc_list *) *slot; + if (list->first) + list->last_before_switch + = list->last->next ? list->last->next : list->last; + return 1; +} + +/* Note in all location lists that text section has changed. */ + +static void +var_location_switch_text_section (void) +{ + if (decl_loc_table == NULL) + return; + + htab_traverse (decl_loc_table, var_location_switch_text_section_1, NULL); +} + +/* Create a new line number table. */ + +static dw_line_info_table * +new_line_info_table (void) +{ + dw_line_info_table *table; + + table = ggc_alloc_cleared_dw_line_info_table_struct (); + table->file_num = 1; + table->line_num = 1; + table->is_stmt = DWARF_LINE_DEFAULT_IS_STMT_START; + + return table; +} + +/* Lookup the "current" table into which we emit line info, so + that we don't have to do it for every source line. */ + +static void +set_cur_line_info_table (section *sec) +{ + dw_line_info_table *table; + + if (sec == text_section) + { + table = text_section_line_info; + if (!table) + { + text_section_line_info = table = new_line_info_table (); + table->end_label = text_end_label; + } + } + else if (sec == cold_text_section) + { + table = cold_text_section_line_info; + if (!table) + { + cold_text_section_line_info = table = new_line_info_table (); + table->end_label = cold_end_label; + } + } + else + { + const char *end_label; + + if (flag_reorder_blocks_and_partition) + { + if (in_cold_section_p) + end_label = crtl->subsections.cold_section_end_label; + else + end_label = crtl->subsections.hot_section_end_label; + } + else + { + char label[MAX_ARTIFICIAL_LABEL_BYTES]; + ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, + current_function_funcdef_no); + end_label = ggc_strdup (label); + } + + table = new_line_info_table (); + table->end_label = end_label; + + VEC_safe_push (dw_line_info_table_p, gc, separate_line_info, table); + } + + cur_line_info_table = table; +} + + /* We need to reset the locations at the beginning of each function. We can't do this in the end_function hook, because the declarations that use the locations won't have been output when @@ -21674,104 +22125,119 @@ dwarf2out_var_location (rtx loc_note) static void dwarf2out_begin_function (tree fun) { - if (function_section (fun) != text_section) + section *sec = function_section (fun); + + if (sec != text_section) have_multiple_function_sections = true; + if (flag_reorder_blocks_and_partition && !cold_text_section) + { + gcc_assert (current_function_decl == fun); + cold_text_section = unlikely_text_section (); + switch_to_section (cold_text_section); + ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label); + switch_to_section (sec); + } + dwarf2out_note_section_used (); + call_site_count = 0; + tail_call_site_count = 0; + + set_cur_line_info_table (sec); +} + +/* Add OPCODE+VAL as an entry at the end of the opcode array in TABLE. */ + +static void +push_dw_line_info_entry (dw_line_info_table *table, + enum dw_line_info_opcode opcode, unsigned int val) +{ + dw_line_info_entry e; + e.opcode = opcode; + e.val = val; + VEC_safe_push (dw_line_info_entry, gc, table->entries, &e); } /* Output a label to mark the beginning of a source code line entry and record information relating to this source line, in 'line_info_table' for later output of the .debug_line section. */ +/* ??? The discriminator parameter ought to be unsigned. */ static void dwarf2out_source_line (unsigned int line, const char *filename, int discriminator, bool is_stmt) { - static bool last_is_stmt = true; - - if (debug_info_level >= DINFO_LEVEL_NORMAL - && line != 0) - { - int file_num = maybe_emit_file (lookup_filename (filename)); + unsigned int file_num; + dw_line_info_table *table; - switch_to_section (current_function_section ()); - - /* If requested, emit something human-readable. */ - if (flag_debug_asm) - fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START, - filename, line); + if (debug_info_level < DINFO_LEVEL_NORMAL || line == 0) + return; - if (DWARF2_ASM_LINE_DEBUG_INFO) - { - /* Emit the .loc directive understood by GNU as. */ - fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line); - if (is_stmt != last_is_stmt) - { - fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0); - last_is_stmt = is_stmt; - } - if (SUPPORTS_DISCRIMINATOR && discriminator != 0) - fprintf (asm_out_file, " discriminator %d", discriminator); - fputc ('\n', asm_out_file); + /* The discriminator column was added in dwarf4. Simplify the below + by simply removing it if we're not supposed to output it. */ + if (dwarf_version < 4 && dwarf_strict) + discriminator = 0; + + table = cur_line_info_table; + file_num = maybe_emit_file (lookup_filename (filename)); + + /* ??? TODO: Elide duplicate line number entries. Traditionally, + the debugger has used the second (possibly duplicate) line number + at the beginning of the function to mark the end of the prologue. + We could eliminate any other duplicates within the function. For + Dwarf3, we ought to include the DW_LNS_set_prologue_end mark in + that second line number entry. */ + /* Recall that this end-of-prologue indication is *not* the same thing + as the end_prologue debug hook. The NOTE_INSN_PROLOGUE_END note, + to which the hook corresponds, follows the last insn that was + emitted by gen_prologue. What we need is to preceed the first insn + that had been emitted after NOTE_INSN_FUNCTION_BEG, i.e. the first + insn that corresponds to something the user wrote. These may be + very different locations once scheduling is enabled. */ + + if (0 && file_num == table->file_num + && line == table->line_num + && discriminator == table->discrim_num + && is_stmt == table->is_stmt) + return; - /* Indicate that line number info exists. */ - line_info_table_in_use++; - } - else if (function_section (current_function_decl) != text_section) - { - dw_separate_line_info_ref line_info; - targetm.asm_out.internal_label (asm_out_file, - SEPARATE_LINE_CODE_LABEL, - separate_line_info_table_in_use); - - /* Expand the line info table if necessary. */ - if (separate_line_info_table_in_use - == separate_line_info_table_allocated) - { - separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; - separate_line_info_table - = GGC_RESIZEVEC (dw_separate_line_info_entry, - separate_line_info_table, - separate_line_info_table_allocated); - memset (separate_line_info_table - + separate_line_info_table_in_use, - 0, - (LINE_INFO_TABLE_INCREMENT - * sizeof (dw_separate_line_info_entry))); - } + switch_to_section (current_function_section ()); - /* Add the new entry at the end of the line_info_table. */ - line_info - = &separate_line_info_table[separate_line_info_table_in_use++]; - line_info->dw_file_num = file_num; - line_info->dw_line_num = line; - line_info->function = current_function_funcdef_no; - } - else - { - dw_line_info_ref line_info; + /* If requested, emit something human-readable. */ + if (flag_debug_asm) + fprintf (asm_out_file, "\t%s %s:%d\n", ASM_COMMENT_START, filename, line); - targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, - line_info_table_in_use); + if (DWARF2_ASM_LINE_DEBUG_INFO) + { + /* Emit the .loc directive understood by GNU as. */ + fprintf (asm_out_file, "\t.loc %d %d 0", file_num, line); + if (is_stmt != table->is_stmt) + fprintf (asm_out_file, " is_stmt %d", is_stmt ? 1 : 0); + if (SUPPORTS_DISCRIMINATOR && discriminator != 0) + fprintf (asm_out_file, " discriminator %d", discriminator); + fputc ('\n', asm_out_file); + } + else + { + unsigned int label_num = ++line_info_label_num; - /* Expand the line info table if necessary. */ - if (line_info_table_in_use == line_info_table_allocated) - { - line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; - line_info_table - = GGC_RESIZEVEC (dw_line_info_entry, line_info_table, - line_info_table_allocated); - memset (line_info_table + line_info_table_in_use, 0, - LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry)); - } + targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, label_num); - /* Add the new entry at the end of the line_info_table. */ - line_info = &line_info_table[line_info_table_in_use++]; - line_info->dw_file_num = file_num; - line_info->dw_line_num = line; - } + push_dw_line_info_entry (table, LI_set_address, label_num); + if (file_num != table->file_num) + push_dw_line_info_entry (table, LI_set_file, file_num); + if (discriminator != table->discrim_num) + push_dw_line_info_entry (table, LI_set_discriminator, discriminator); + if (is_stmt != table->is_stmt) + push_dw_line_info_entry (table, LI_negate_stmt, 0); + push_dw_line_info_entry (table, LI_set_line, line); } + + table->file_num = file_num; + table->line_num = line; + table->discrim_num = discriminator; + table->is_stmt = is_stmt; + table->in_use = true; } /* Record the beginning of a new source file. */ @@ -21779,7 +22245,7 @@ dwarf2out_source_line (unsigned int line, const char *filename, static void dwarf2out_start_source_file (unsigned int lineno, const char *filename) { - if (flag_eliminate_dwarf2_dups && dwarf_version < 4) + if (flag_eliminate_dwarf2_dups && ! use_debug_types) { /* Record the beginning of the file for break_out_includes. */ dw_die_ref bincl_die; @@ -21803,7 +22269,7 @@ dwarf2out_start_source_file (unsigned int lineno, const char *filename) static void dwarf2out_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED) { - if (flag_eliminate_dwarf2_dups && dwarf_version < 4) + if (flag_eliminate_dwarf2_dups && ! use_debug_types) /* Record the end of the file for break_out_includes. */ new_die (DW_TAG_GNU_EINCL, comp_unit_die (), NULL); @@ -21917,6 +22383,11 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) decl_loc_table = htab_create_ggc (10, decl_loc_table_hash, decl_loc_table_eq, NULL); + /* Allocate the cached_dw_loc_list_table. */ + cached_dw_loc_list_table + = htab_create_ggc (10, cached_dw_loc_list_table_hash, + cached_dw_loc_list_table_eq, NULL); + /* Allocate the initial hunk of the decl_scope_table. */ decl_scope_table = VEC_alloc (tree, gc, 256); @@ -21927,22 +22398,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) /* Zero-th entry is allocated, but unused. */ abbrev_die_table_in_use = 1; - /* Allocate the initial hunk of the line_info_table. */ - line_info_table = ggc_alloc_cleared_vec_dw_line_info_entry - (LINE_INFO_TABLE_INCREMENT); - line_info_table_allocated = LINE_INFO_TABLE_INCREMENT; - - /* Zero-th entry is allocated, but unused. */ - line_info_table_in_use = 1; - /* Allocate the pubtypes and pubnames vectors. */ pubname_table = VEC_alloc (pubname_entry, gc, 32); pubtype_table = VEC_alloc (pubname_entry, gc, 32); - /* Allocate the table that maps insn UIDs to vtable slot indexes. */ - vcall_insn_table = htab_create_ggc (10, vcall_insn_table_hash, - vcall_insn_table_eq, NULL); - incomplete_types = VEC_alloc (tree, gc, 64); used_rtx_array = VEC_alloc (rtx, gc, 32); @@ -21963,10 +22422,6 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) SECTION_DEBUG, NULL); debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION, SECTION_DEBUG, NULL); - debug_dcall_section = get_section (DEBUG_DCALL_SECTION, - SECTION_DEBUG, NULL); - debug_vcall_section = get_section (DEBUG_VCALL_SECTION, - SECTION_DEBUG, NULL); debug_str_section = get_section (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); debug_ranges_section = get_section (DEBUG_RANGES_SECTION, @@ -21996,13 +22451,6 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) switch_to_section (text_section); ASM_OUTPUT_LABEL (asm_out_file, text_section_label); - if (flag_reorder_blocks_and_partition) - { - cold_text_section = unlikely_text_section (); - switch_to_section (cold_text_section); - ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label); - } - } /* Called before cgraph_optimize starts outputtting functions, variables @@ -22014,7 +22462,7 @@ dwarf2out_assembly_start (void) if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE && dwarf2out_do_cfi_asm () && (!(flag_unwind_tables || flag_exceptions) - || targetm.except_unwind_info () != UI_DWARF2)) + || targetm.except_unwind_info (&global_options) != UI_DWARF2)) fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n"); } @@ -22078,7 +22526,7 @@ prune_unused_types_walk_attribs (dw_die_ref die) /* A reference to another DIE. Make sure that it will get emitted. If it was broken out into a comdat group, don't follow it. */ - if (dwarf_version < 4 + if (! use_debug_types || a->dw_attr == DW_AT_specification || a->dw_attr_val.v.val_die_ref.die->die_id.die_type_node == NULL) prune_unused_types_mark (a->dw_attr_val.v.val_die_ref.die, 1); @@ -22090,6 +22538,32 @@ prune_unused_types_walk_attribs (dw_die_ref die) } } +/* Mark the generic parameters and arguments children DIEs of DIE. */ + +static void +prune_unused_types_mark_generic_parms_dies (dw_die_ref die) +{ + dw_die_ref c; + + if (die == NULL || die->die_child == NULL) + return; + c = die->die_child; + do + { + switch (c->die_tag) + { + case DW_TAG_template_type_param: + case DW_TAG_template_value_param: + case DW_TAG_GNU_template_template_param: + case DW_TAG_GNU_template_parameter_pack: + prune_unused_types_mark (c, 1); + break; + default: + break; + } + c = c->die_sib; + } while (c && c != die->die_child); +} /* Mark DIE as being used. If DOKIDS is true, then walk down to DIE's children. */ @@ -22103,6 +22577,10 @@ prune_unused_types_mark (dw_die_ref die, int dokids) { /* We haven't done this node yet. Mark it as used. */ die->die_mark = 1; + /* If this is the DIE of a generic type instantiation, + mark the children DIEs that describe its generic parms and + args. */ + prune_unused_types_mark_generic_parms_dies (die); /* We also have to mark its parents as used. (But we don't want to mark our parents' kids due to this.) */ @@ -22129,7 +22607,7 @@ prune_unused_types_mark (dw_die_ref die, int dokids) breaking out types into comdat sections, do this for all type definitions. */ if (die->die_tag == DW_TAG_array_type - || (dwarf_version >= 4 + || (use_debug_types && is_type_die (die) && ! is_declaration_die (die))) FOR_EACH_CHILD (die, c, prune_unused_types_mark (c, 1)); else @@ -22337,7 +22815,6 @@ prune_unused_types (void) limbo_die_node *node; comdat_type_node *ctnode; pubname_ref pub; - dcall_entry *dcall; #if ENABLE_ASSERT_CHECKING /* All the marks should already be clear. */ @@ -22362,15 +22839,9 @@ prune_unused_types (void) } /* Also set the mark on nodes referenced from the - pubname_table or arange_table. */ + pubname_table. */ FOR_EACH_VEC_ELT (pubname_entry, pubname_table, i, pub) prune_unused_types_mark (pub->die, 1); - for (i = 0; i < arange_table_in_use; i++) - prune_unused_types_mark (arange_table[i], 1); - - /* Mark nodes referenced from the direct call table. */ - FOR_EACH_VEC_ELT (dcall_entry, dcall_table, i, dcall) - prune_unused_types_mark (dcall->targ_die, 1); /* Get rid of nodes that aren't marked; and update the string counts. */ if (debug_str_hash && debug_str_hash_forced) @@ -22485,9 +22956,16 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED) } if (GET_CODE (rtl) == SYMBOL_REF - && SYMBOL_REF_DECL (rtl) - && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl))) - return 1; + && SYMBOL_REF_DECL (rtl)) + { + if (TREE_CONSTANT_POOL_ADDRESS_P (rtl)) + { + if (!TREE_ASM_WRITTEN (DECL_INITIAL (SYMBOL_REF_DECL (rtl)))) + return 1; + } + else if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl))) + return 1; + } if (GET_CODE (rtl) == CONST && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL)) @@ -22536,30 +23014,53 @@ resolve_addr (dw_die_ref die) { dw_die_ref c; dw_attr_ref a; - dw_loc_list_ref *curr; + dw_loc_list_ref *curr, *start, loc; unsigned ix; FOR_EACH_VEC_ELT (dw_attr_node, die->die_attr, ix, a) switch (AT_class (a)) { case dw_val_class_loc_list: - curr = AT_loc_list_ptr (a); - while (*curr) + start = curr = AT_loc_list_ptr (a); + loc = *curr; + gcc_assert (loc); + /* The same list can be referenced more than once. See if we have + already recorded the result from a previous pass. */ + if (loc->replaced) + *curr = loc->dw_loc_next; + else if (!loc->resolved_addr) { - if (!resolve_addr_in_expr ((*curr)->expr)) + /* As things stand, we do not expect or allow one die to + reference a suffix of another die's location list chain. + References must be identical or completely separate. + There is therefore no need to cache the result of this + pass on any list other than the first; doing so + would lead to unnecessary writes. */ + while (*curr) { - dw_loc_list_ref next = (*curr)->dw_loc_next; - if (next && (*curr)->ll_symbol) + gcc_assert (!(*curr)->replaced && !(*curr)->resolved_addr); + if (!resolve_addr_in_expr ((*curr)->expr)) { - gcc_assert (!next->ll_symbol); - next->ll_symbol = (*curr)->ll_symbol; + dw_loc_list_ref next = (*curr)->dw_loc_next; + if (next && (*curr)->ll_symbol) + { + gcc_assert (!next->ll_symbol); + next->ll_symbol = (*curr)->ll_symbol; + } + *curr = next; } - *curr = next; + else + curr = &(*curr)->dw_loc_next; } + if (loc == *start) + loc->resolved_addr = 1; else - curr = &(*curr)->dw_loc_next; + { + loc->replaced = 1; + loc->dw_loc_next = *start; + } } - if (!AT_loc_list (a)) + if (!*start) { remove_AT (die, a->dw_attr); ix--; @@ -22579,6 +23080,30 @@ resolve_addr (dw_die_ref die) remove_AT (die, a->dw_attr); ix--; } + if (die->die_tag == DW_TAG_GNU_call_site + && a->dw_attr == DW_AT_abstract_origin) + { + tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr); + dw_die_ref tdie = lookup_decl_die (tdecl); + if (tdie == NULL + && DECL_EXTERNAL (tdecl) + && DECL_ABSTRACT_ORIGIN (tdecl) == NULL_TREE) + { + force_decl_die (tdecl); + tdie = lookup_decl_die (tdecl); + } + if (tdie) + { + a->dw_attr_val.val_class = dw_val_class_die_ref; + a->dw_attr_val.v.val_die_ref.die = tdie; + a->dw_attr_val.v.val_die_ref.external = 0; + } + else + { + remove_AT (die, a->dw_attr); + ix--; + } + } break; default: break; @@ -22711,6 +23236,9 @@ hash_loc_operands (dw_loc_descr_ref loc, hashval_t hash) case DW_OP_GNU_implicit_pointer: hash = iterative_hash_object (val2->v.val_int, hash); break; + case DW_OP_GNU_entry_value: + hash = hash_loc_operands (val1->v.val_loc, hash); + break; default: /* Other codes have no operands. */ @@ -22862,12 +23390,14 @@ compare_loc_operands (dw_loc_descr_ref x, dw_loc_descr_ref y) && valx2->v.val_int == valy2->v.val_int; case DW_OP_addr: hash_addr: - return rtx_equal_p (valx1->v.val_addr, valx2->v.val_addr); + return rtx_equal_p (valx1->v.val_addr, valy1->v.val_addr); case DW_OP_GNU_implicit_pointer: return valx1->val_class == dw_val_class_die_ref && valx1->val_class == valy1->val_class && valx1->v.val_die_ref.die == valy1->v.val_die_ref.die && valx2->v.val_int == valy2->v.val_int; + case DW_OP_GNU_entry_value: + return compare_loc_operands (valx1->v.val_loc, valy1->v.val_loc); default: /* Other codes have no operands. */ return true; @@ -22965,9 +23495,9 @@ dwarf2out_finish (const char *filename) limbo_die_node *node, *next_node; comdat_type_node *ctnode; htab_t comdat_type_table; - dw_die_ref die = 0; unsigned int i; + gen_scheduled_generic_parms_dies (); gen_remaining_tmpl_value_param_die_attribute (); /* Add the name for the main input file now. We delayed this from @@ -22988,6 +23518,7 @@ dwarf2out_finish (const char *filename) add_location_or_const_value_attribute ( VEC_index (deferred_locations, deferred_locations_list, i)->die, VEC_index (deferred_locations, deferred_locations_list, i)->variable, + false, DW_AT_location); } @@ -22998,8 +23529,8 @@ dwarf2out_finish (const char *filename) instance. */ for (node = limbo_die_list; node; node = next_node) { + dw_die_ref die = node->die; next_node = node->next; - die = node->die; if (die->die_parent == NULL) { @@ -23071,11 +23602,11 @@ dwarf2out_finish (const char *filename) /* Generate separate CUs for each of the include files we've seen. They will go into limbo_die_list. */ - if (flag_eliminate_dwarf2_dups && dwarf_version < 4) + if (flag_eliminate_dwarf2_dups && ! use_debug_types) break_out_includes (comp_unit_die ()); /* Generate separate COMDAT sections for type DIEs. */ - if (dwarf_version >= 4) + if (use_debug_types) { break_out_comdat_types (comp_unit_die ()); @@ -23108,38 +23639,33 @@ dwarf2out_finish (const char *filename) /* Output a terminator label for the .text section. */ switch_to_section (text_section); targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0); - if (flag_reorder_blocks_and_partition) + if (cold_text_section) { - switch_to_section (unlikely_text_section ()); + switch_to_section (cold_text_section); targetm.asm_out.internal_label (asm_out_file, COLD_END_LABEL, 0); } /* We can only use the low/high_pc attributes if all of the code was in .text. */ - if (!have_multiple_function_sections - || !(dwarf_version >= 3 || !dwarf_strict)) + if (!have_multiple_function_sections + || (dwarf_version < 3 && dwarf_strict)) { - add_AT_lbl_id (comp_unit_die (), DW_AT_low_pc, text_section_label); - add_AT_lbl_id (comp_unit_die (), DW_AT_high_pc, text_end_label); + /* Don't add if the CU has no associated code. */ + if (text_section_used) + { + add_AT_lbl_id (comp_unit_die (), DW_AT_low_pc, text_section_label); + add_AT_lbl_id (comp_unit_die (), DW_AT_high_pc, text_end_label); + } } - else { unsigned fde_idx = 0; bool range_list_added = false; - /* We need to give .debug_loc and .debug_ranges an appropriate - "base address". Use zero so that these addresses become - absolute. Historically, we've emitted the unexpected - DW_AT_entry_pc instead of DW_AT_low_pc for this purpose. - Emit both to give time for other tools to adapt. */ - add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx); - add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx); - if (text_section_used) add_ranges_by_labels (comp_unit_die (), text_section_label, text_end_label, &range_list_added); - if (flag_reorder_blocks_and_partition && cold_text_section_used) + if (cold_text_section_used) add_ranges_by_labels (comp_unit_die (), cold_text_section_label, cold_end_label, &range_list_added); @@ -23147,26 +23673,27 @@ dwarf2out_finish (const char *filename) { dw_fde_ref fde = &fde_table[fde_idx]; - if (fde->dw_fde_switched_sections) - { - if (!fde->in_std_section) - add_ranges_by_labels (comp_unit_die (), - fde->dw_fde_hot_section_label, - fde->dw_fde_hot_section_end_label, - &range_list_added); - if (!fde->cold_in_std_section) - add_ranges_by_labels (comp_unit_die (), - fde->dw_fde_unlikely_section_label, - fde->dw_fde_unlikely_section_end_label, - &range_list_added); - } - else if (!fde->in_std_section) + if (!fde->in_std_section) add_ranges_by_labels (comp_unit_die (), fde->dw_fde_begin, fde->dw_fde_end, &range_list_added); + if (fde->dw_fde_second_begin && !fde->second_in_std_section) + add_ranges_by_labels (comp_unit_die (), fde->dw_fde_second_begin, + fde->dw_fde_second_end, &range_list_added); } if (range_list_added) - add_ranges (NULL); + { + /* We need to give .debug_loc and .debug_ranges an appropriate + "base address". Use zero so that these addresses become + absolute. Historically, we've emitted the unexpected + DW_AT_entry_pc instead of DW_AT_low_pc for this purpose. + Emit both to give time for other tools to adapt. */ + add_AT_addr (comp_unit_die (), DW_AT_low_pc, const0_rtx); + if (! dwarf_strict && dwarf_version < 4) + add_AT_addr (comp_unit_die (), DW_AT_entry_pc, const0_rtx); + + add_ranges (NULL); + } } if (debug_info_level >= DINFO_LEVEL_NORMAL) @@ -23177,7 +23704,7 @@ dwarf2out_finish (const char *filename) add_AT_macptr (comp_unit_die (), DW_AT_macro_info, macinfo_section_label); if (have_location_lists) - optimize_location_lists (die); + optimize_location_lists (comp_unit_die ()); /* Output all of the compilation units. We put the main one last so that the offsets are available to output_pubnames. */ @@ -23222,7 +23749,7 @@ dwarf2out_finish (const char *filename) ASM_GENERATE_INTERNAL_LABEL (loc_section_label, DEBUG_LOC_SECTION_LABEL, 0); ASM_OUTPUT_LABEL (asm_out_file, loc_section_label); - output_location_lists (die); + output_location_lists (comp_unit_die ()); } /* Output public names table if necessary. */ @@ -23262,24 +23789,21 @@ dwarf2out_finish (const char *filename) } } - /* Output direct and virtual call tables if necessary. */ - if (!VEC_empty (dcall_entry, dcall_table)) + /* Output the address range information. We only put functions in the + arange table, so don't write it out if we don't have any. */ + if (info_section_emitted) { - switch_to_section (debug_dcall_section); - output_dcall_table (); - } - if (!VEC_empty (vcall_entry, vcall_table)) - { - switch_to_section (debug_vcall_section); - output_vcall_table (); - } + unsigned long aranges_length = size_of_aranges (); - /* Output the address range information. We only put functions in the arange - table, so don't write it out if we don't have any. */ - if (fde_table_in_use) - { - switch_to_section (debug_aranges_section); - output_aranges (); + /* Empty .debug_aranges would contain just header and + terminating 0,0. */ + if (aranges_length + != (unsigned long) (DWARF_ARANGES_HEADER_SIZE + + 2 * DWARF2_ADDR_SIZE)) + { + switch_to_section (debug_aranges_section); + output_aranges (aranges_length); + } } /* Output ranges section if necessary. */