X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fdwarf2out.c;h=f954d6e2ea29aa032216565241fc6671004b3f39;hp=7d82c47679a101738c36f77524485efe875eb709;hb=2452254d308937f722a81173c4ef1cd43ab67107;hpb=a974aa3e442eed4ff62ce7796e268d9648e88482 diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 7d82c47679a..f954d6e2ea2 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -74,7 +74,7 @@ along with GCC; see the file COPYING3. If not see #include "expr.h" #include "libfuncs.h" #include "except.h" -#include "dwarf2.h" +#include "elf/dwarf2.h" #include "dwarf2out.h" #include "dwarf2asm.h" #include "toplev.h" @@ -91,7 +91,9 @@ along with GCC; see the file COPYING3. If not see #include "input.h" #ifdef DWARF2_DEBUGGING_INFO -static void dwarf2out_source_line (unsigned int, const char *); +static void dwarf2out_source_line (unsigned int, const char *, int, bool); + +static rtx last_var_location_insn; #endif #ifndef DWARF2_FRAME_INFO @@ -220,8 +222,7 @@ enum dw_cfi_oprnd_type { dw_cfi_oprnd_loc }; -typedef union dw_cfi_oprnd_struct GTY(()) -{ +typedef union GTY(()) dw_cfi_oprnd_struct { unsigned int GTY ((tag ("dw_cfi_oprnd_reg_num"))) dw_cfi_reg_num; HOST_WIDE_INT GTY ((tag ("dw_cfi_oprnd_offset"))) dw_cfi_offset; const char * GTY ((tag ("dw_cfi_oprnd_addr"))) dw_cfi_addr; @@ -229,8 +230,7 @@ typedef union dw_cfi_oprnd_struct GTY(()) } dw_cfi_oprnd; -typedef struct dw_cfi_struct GTY(()) -{ +typedef struct GTY(()) dw_cfi_struct { dw_cfi_ref dw_cfi_next; enum dwarf_call_frame_info dw_cfi_opc; dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)"))) @@ -245,12 +245,12 @@ 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 cfa_loc GTY(()) -{ +typedef struct GTY(()) cfa_loc { HOST_WIDE_INT offset; HOST_WIDE_INT base_offset; unsigned int reg; - int indirect; /* 1 if CFA is accessed via a dereference. */ + BOOL_BITFIELD indirect : 1; /* 1 if CFA is accessed via a dereference. */ + BOOL_BITFIELD in_use : 1; /* 1 if a saved cfa is stored here. */ } dw_cfa_location; /* All call frame descriptions (FDE's) in the GCC generated DWARF @@ -259,8 +259,7 @@ typedef struct cfa_loc GTY(()) CIE obviates the need to keep track of multiple CIE's in the DWARF generation routines below. */ -typedef struct dw_fde_struct GTY(()) -{ +typedef struct GTY(()) dw_fde_struct { tree decl; const char *dw_fde_begin; const char *dw_fde_current_label; @@ -320,8 +319,6 @@ dw_fde_node; #define DWARF_INITIAL_LENGTH_SIZE (DWARF_OFFSET_SIZE == 4 ? 4 : 12) #endif -#define DWARF_VERSION 2 - /* Round SIZE up to the nearest BOUNDARY. */ #define DWARF_ROUND(SIZE,BOUNDARY) \ ((((SIZE) + (BOUNDARY) - 1) / (BOUNDARY)) * (BOUNDARY)) @@ -376,11 +373,10 @@ static GTY(()) dw_cfi_ref cie_cfi_head; static unsigned current_funcdef_fde; #endif -struct indirect_string_node GTY(()) -{ +struct GTY(()) indirect_string_node { const char *str; unsigned int refcount; - unsigned int form; + enum dwarf_form form; char *label; }; @@ -409,7 +405,7 @@ static const char *dwarf_cfi_name (unsigned); static dw_cfi_ref new_cfi (void); static void add_cfi (dw_cfi_ref *, dw_cfi_ref); static void add_fde_cfi (const char *, dw_cfi_ref); -static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *); +static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *, dw_cfa_location *); static void lookup_cfa (dw_cfa_location *); static void reg_save (const char *, unsigned, unsigned, HOST_WIDE_INT); #ifdef DWARF2_UNWIND_INFO @@ -528,6 +524,25 @@ init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c) emit_move_insn (adjust_address (mem, mode, offset), GEN_INT (size)); } +/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder. */ + +static inline HOST_WIDE_INT +div_data_align (HOST_WIDE_INT off) +{ + HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT; + gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off); + return r; +} + +/* Return true if we need a signed version of a given opcode + (e.g. DW_CFA_offset_extended_sf vs DW_CFA_offset_extended). */ + +static inline bool +need_data_align_sf_opcode (HOST_WIDE_INT off) +{ + return DWARF_CIE_DATA_ALIGNMENT < 0 ? off > 0 : off < 0; +} + /* Generate code to initialize the register size table. */ void @@ -673,7 +688,10 @@ add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi) /* When DRAP is used, CFA is defined with an expression. Redefine CFA may lead to a different CFA value. */ - if (fde && fde->drap_reg != INVALID_REGNUM) + /* ??? Of course, this heuristic fails when we're annotating epilogues, + because of course we'll always want to redefine the CFA back to the + stack pointer on the way out. Where should we move this check? */ + if (0 && fde && fde->drap_reg != INVALID_REGNUM) switch (cfi->dw_cfi_opc) { case DW_CFA_def_cfa_register: @@ -694,14 +712,15 @@ add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi) *p = cfi; } -/* Generate a new label for the CFI info to refer to. */ +/* Generate a new label for the CFI info to refer to. FORCE is true + if a label needs to be output even when using .cfi_* directives. */ char * -dwarf2out_cfi_label (void) +dwarf2out_cfi_label (bool force) { static char label[20]; - if (dwarf2out_do_cfi_asm ()) + if (!force && dwarf2out_do_cfi_asm ()) { /* In this case, we will be emitting the asm directive instead of the label, so just return a placeholder to keep the rest of the @@ -717,23 +736,88 @@ dwarf2out_cfi_label (void) return label; } +/* True if remember_state should be emitted before following CFI directive. */ +static bool emit_cfa_remember; + /* Add CFI to the current fde at the PC value indicated by LABEL if specified, or to the CIE if LABEL is NULL. */ static void add_fde_cfi (const char *label, dw_cfi_ref cfi) { - dw_cfi_ref *list_head = &cie_cfi_head; + dw_cfi_ref *list_head; + + if (emit_cfa_remember) + { + dw_cfi_ref cfi_remember; + + /* Emit the state save. */ + emit_cfa_remember = false; + cfi_remember = new_cfi (); + cfi_remember->dw_cfi_opc = DW_CFA_remember_state; + add_fde_cfi (label, cfi_remember); + } + + list_head = &cie_cfi_head; if (dwarf2out_do_cfi_asm ()) { if (label) { + dw_fde_ref fde = current_fde (); + + gcc_assert (fde != NULL); + + /* We still have to add the cfi to the list so that lookup_cfa + works later on. When -g2 and above we even need to force + emitting of CFI labels and add to list a DW_CFA_set_loc for + convert_cfa_to_fb_loc_list purposes. If we're generating + DWARF3 output we use DW_OP_call_frame_cfa and so don't use + convert_cfa_to_fb_loc_list. */ + if (dwarf_version == 2 + && debug_info_level > DINFO_LEVEL_TERSE + && (write_symbols == DWARF2_DEBUG + || write_symbols == VMS_AND_DWARF2_DEBUG)) + { + switch (cfi->dw_cfi_opc) + { + case DW_CFA_def_cfa_offset: + case DW_CFA_def_cfa_offset_sf: + case DW_CFA_def_cfa_register: + case DW_CFA_def_cfa: + case DW_CFA_def_cfa_sf: + case DW_CFA_def_cfa_expression: + case DW_CFA_restore_state: + if (*label == 0 || strcmp (label, "") == 0) + label = dwarf2out_cfi_label (true); + + if (fde->dw_fde_current_label == NULL + || strcmp (label, fde->dw_fde_current_label) != 0) + { + dw_cfi_ref xcfi; + + label = xstrdup (label); + + /* Set the location counter to the new label. */ + xcfi = new_cfi (); + /* It doesn't metter whether DW_CFA_set_loc + or DW_CFA_advance_loc4 is added here, those aren't + emitted into assembly, only looked up by + convert_cfa_to_fb_loc_list. */ + xcfi->dw_cfi_opc = DW_CFA_set_loc; + xcfi->dw_cfi_oprnd1.dw_cfi_addr = label; + add_cfi (&fde->dw_fde_cfi, xcfi); + fde->dw_fde_current_label = label; + } + break; + default: + break; + } + } + output_cfi_directive (cfi); - /* We still have to add the cfi to the list so that - lookup_cfa works later on. */ - list_head = ¤t_fde ()->dw_fde_cfi; + list_head = &fde->dw_fde_cfi; } /* ??? If this is a CFI for the CIE, we don't emit. This assumes that the standard CIE contents that the assembler @@ -748,7 +832,7 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) gcc_assert (fde != NULL); if (*label == 0) - label = dwarf2out_cfi_label (); + label = dwarf2out_cfi_label (false); if (fde->dw_fde_current_label == NULL || strcmp (label, fde->dw_fde_current_label) != 0) @@ -779,7 +863,7 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) /* Subroutine of lookup_cfa. */ static void -lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc) +lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember) { switch (cfi->dw_cfi_opc) { @@ -798,6 +882,18 @@ lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc) case DW_CFA_def_cfa_expression: get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc); break; + + case DW_CFA_remember_state: + gcc_assert (!remember->in_use); + *remember = *loc; + remember->in_use = 1; + break; + case DW_CFA_restore_state: + gcc_assert (remember->in_use); + *loc = *remember; + remember->in_use = 0; + break; + default: break; } @@ -810,19 +906,19 @@ lookup_cfa (dw_cfa_location *loc) { dw_cfi_ref cfi; dw_fde_ref fde; + dw_cfa_location remember; + memset (loc, 0, sizeof (*loc)); loc->reg = INVALID_REGNUM; - loc->offset = 0; - loc->indirect = 0; - loc->base_offset = 0; + remember = *loc; for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) - lookup_cfa_1 (cfi, loc); + lookup_cfa_1 (cfi, loc, &remember); fde = current_fde (); if (fde) for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next) - lookup_cfa_1 (cfi, loc); + lookup_cfa_1 (cfi, loc, &remember); } /* The current rule for calculating the DWARF2 canonical frame address. */ @@ -832,6 +928,9 @@ static dw_cfa_location cfa; from the CFA. */ static dw_cfa_location cfa_store; +/* The current save location around an epilogue. */ +static dw_cfa_location cfa_remember; + /* The running total of the size of arguments pushed onto the stack. */ static HOST_WIDE_INT args_size; @@ -895,7 +994,7 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p) the CFA register did not change but the offset did. The data factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or in the assembler via the .cfi_def_cfa_offset directive. */ - if (loc.offset < 0) + if (need_data_align_sf_opcode (loc.offset)) cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf; else cfi->dw_cfi_opc = DW_CFA_def_cfa_offset; @@ -922,7 +1021,7 @@ def_cfa_1 (const char *label, dw_cfa_location *loc_p) the specified offset. The data factoring for DW_CFA_def_cfa_sf happens in output_cfi, or in the assembler via the .cfi_def_cfa directive. */ - if (loc.offset < 0) + if (need_data_align_sf_opcode (loc.offset)) cfi->dw_cfi_opc = DW_CFA_def_cfa_sf; else cfi->dw_cfi_opc = DW_CFA_def_cfa; @@ -970,7 +1069,7 @@ reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT } else if (sreg == INVALID_REGNUM) { - if (offset < 0) + if (need_data_align_sf_opcode (offset)) cfi->dw_cfi_opc = DW_CFA_offset_extended_sf; else if (reg & ~0x3f) cfi->dw_cfi_opc = DW_CFA_offset_extended; @@ -1098,7 +1197,7 @@ initial_return_save (rtx rtl) /* The return address is at some offset from any value we can actually load. For instance, on the SPARC it is in %i7+8. Just ignore the offset for now; it doesn't matter for unwinding frames. */ - gcc_assert (GET_CODE (XEXP (rtl, 1)) == CONST_INT); + gcc_assert (CONST_INT_P (XEXP (rtl, 1))); initial_return_save (XEXP (rtl, 0)); return; @@ -1140,7 +1239,7 @@ stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size, if (! (code == PLUS || code == MINUS) || XEXP (src, 0) != stack_pointer_rtx - || GET_CODE (XEXP (src, 1)) != CONST_INT) + || !CONST_INT_P (XEXP (src, 1))) return 0; /* (set (reg sp) (plus (reg sp) (const_int))) */ @@ -1167,7 +1266,7 @@ stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size, rtx val = XEXP (XEXP (src, 1), 1); /* We handle only adjustments by constant amount. */ gcc_assert (GET_CODE (XEXP (src, 1)) == PLUS - && GET_CODE (val) == CONST_INT); + && CONST_INT_P (val)); offset = -INTVAL (val); break; } @@ -1217,8 +1316,7 @@ compute_barrier_args_size_1 (rtx insn, HOST_WIDE_INT cur_args_size, if (! RTX_FRAME_RELATED_P (insn)) { - if (prologue_epilogue_contains (insn) - || sibcall_epilogue_contains (insn)) + if (prologue_epilogue_contains (insn)) /* Nothing */; else if (GET_CODE (PATTERN (insn)) == SET) offset = stack_adjust_offset (PATTERN (insn), cur_args_size, 0); @@ -1391,7 +1489,7 @@ dwarf2out_stack_adjust (rtx insn, bool after_p) with this function. Proper support would require all frame-related insns to be marked, and to be able to handle saving state around epilogues textually in the middle of the function. */ - if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn)) + if (prologue_epilogue_contains (insn)) return; /* If INSN is an instruction from target of an annulled branch, the @@ -1464,7 +1562,7 @@ dwarf2out_stack_adjust (rtx insn, bool after_p) if (offset == 0) return; - label = dwarf2out_cfi_label (); + label = dwarf2out_cfi_label (false); dwarf2out_args_size_adjust (offset, label); } @@ -1498,8 +1596,7 @@ dwarf2out_args_size_adjust (HOST_WIDE_INT offset, const char *label) of the prologue or (b) the register is clobbered. This clusters register saves so that there are fewer pc advances. */ -struct queued_reg_save GTY(()) -{ +struct GTY(()) queued_reg_save { struct queued_reg_save *next; rtx reg; HOST_WIDE_INT cfa_offset; @@ -1509,7 +1606,7 @@ struct queued_reg_save GTY(()) static GTY(()) struct queued_reg_save *queued_reg_saves; /* The caller's ORIG_REG is saved in SAVED_IN_REG. */ -struct reg_saved_in_data GTY(()) { +struct GTY(()) reg_saved_in_data { rtx orig_reg; rtx saved_in_reg; }; @@ -1666,6 +1763,156 @@ reg_saved_in (rtx reg) value, not an offset. */ static dw_cfa_location cfa_temp; +/* A subroutine of dwarf2out_frame_debug, process a REG_DEF_CFA note. */ + +static void +dwarf2out_frame_debug_def_cfa (rtx pat, const char *label) +{ + memset (&cfa, 0, sizeof (cfa)); + + switch (GET_CODE (pat)) + { + case PLUS: + cfa.reg = REGNO (XEXP (pat, 0)); + cfa.offset = INTVAL (XEXP (pat, 1)); + break; + + case REG: + cfa.reg = REGNO (pat); + break; + + default: + /* Recurse and define an expression. */ + gcc_unreachable (); + } + + def_cfa_1 (label, &cfa); +} + +/* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */ + +static void +dwarf2out_frame_debug_adjust_cfa (rtx pat, const char *label) +{ + rtx src, dest; + + gcc_assert (GET_CODE (pat) == SET); + dest = XEXP (pat, 0); + src = XEXP (pat, 1); + + switch (GET_CODE (src)) + { + case PLUS: + gcc_assert (REGNO (XEXP (src, 0)) == cfa.reg); + cfa.offset -= INTVAL (XEXP (src, 1)); + break; + + case REG: + break; + + default: + gcc_unreachable (); + } + + cfa.reg = REGNO (dest); + gcc_assert (cfa.indirect == 0); + + def_cfa_1 (label, &cfa); +} + +/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note. */ + +static void +dwarf2out_frame_debug_cfa_offset (rtx set, const char *label) +{ + HOST_WIDE_INT offset; + rtx src, addr, span; + + src = XEXP (set, 1); + addr = XEXP (set, 0); + gcc_assert (MEM_P (addr)); + addr = XEXP (addr, 0); + + /* As documented, only consider extremely simple addresses. */ + switch (GET_CODE (addr)) + { + case REG: + gcc_assert (REGNO (addr) == cfa.reg); + offset = -cfa.offset; + break; + case PLUS: + gcc_assert (REGNO (XEXP (addr, 0)) == cfa.reg); + offset = INTVAL (XEXP (addr, 1)) - cfa.offset; + break; + default: + gcc_unreachable (); + } + + span = targetm.dwarf_register_span (src); + + /* ??? We'd like to use queue_reg_save, but we need to come up with + a different flushing heuristic for epilogues. */ + if (!span) + reg_save (label, DWARF_FRAME_REGNUM (REGNO (src)), INVALID_REGNUM, offset); + else + { + /* We have a PARALLEL describing where the contents of SRC live. + Queue register saves for each piece of the PARALLEL. */ + int par_index; + int limit; + HOST_WIDE_INT span_offset = offset; + + gcc_assert (GET_CODE (span) == PARALLEL); + + limit = XVECLEN (span, 0); + for (par_index = 0; par_index < limit; par_index++) + { + rtx elem = XVECEXP (span, 0, par_index); + + reg_save (label, DWARF_FRAME_REGNUM (REGNO (elem)), + INVALID_REGNUM, span_offset); + span_offset += GET_MODE_SIZE (GET_MODE (elem)); + } + } +} + +/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_REGISTER note. */ + +static void +dwarf2out_frame_debug_cfa_register (rtx set, const char *label) +{ + rtx src, dest; + unsigned sregno, dregno; + + src = XEXP (set, 1); + dest = XEXP (set, 0); + + if (src == pc_rtx) + sregno = DWARF_FRAME_RETURN_COLUMN; + else + sregno = DWARF_FRAME_REGNUM (REGNO (src)); + + dregno = DWARF_FRAME_REGNUM (REGNO (dest)); + + /* ??? We'd like to use queue_reg_save, but we need to come up with + a different flushing heuristic for epilogues. */ + reg_save (label, sregno, dregno, 0); +} + +/* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */ + +static void +dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label) +{ + dw_cfi_ref cfi = new_cfi (); + unsigned int regno = DWARF_FRAME_REGNUM (REGNO (reg)); + + cfi->dw_cfi_opc = (regno & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore); + cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno; + + add_fde_cfi (label, cfi); +} + /* Record call frame debugging information for an expression EXPR, which either sets SP or FP (adjusting how we calculate the frame address) or saves a register to the stack or another register. @@ -1938,17 +2185,17 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) fde = current_fde (); - if (GET_CODE (src) == REG + if (REG_P (src) && fde && fde->drap_reg == REGNO (src) && (fde->drap_reg_saved - || GET_CODE (dest) == REG)) + || REG_P (dest))) { /* Rule 20 */ /* If we are saving dynamic realign argument pointer to a register, the destination is virtual dynamic realign argument pointer. It may be used to access argument. */ - if (GET_CODE (dest) == REG) + if (REG_P (dest)) { gcc_assert (fde->vdrap_reg == INVALID_REGNUM); fde->vdrap_reg = REGNO (dest); @@ -2049,7 +2296,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) gcc_assert (REG_P (XEXP (src, 0)) && (unsigned) REGNO (XEXP (src, 0)) == cfa.reg - && GET_CODE (XEXP (src, 1)) == CONST_INT); + && CONST_INT_P (XEXP (src, 1))); offset = INTVAL (XEXP (src, 1)); if (GET_CODE (src) != MINUS) offset = -offset; @@ -2063,7 +2310,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) /* Rule 4 */ if (REG_P (XEXP (src, 0)) && REGNO (XEXP (src, 0)) == cfa.reg - && GET_CODE (XEXP (src, 1)) == CONST_INT) + && CONST_INT_P (XEXP (src, 1))) { /* Setting a temporary CFA register that will be copied into the FP later on. */ @@ -2089,7 +2336,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) /* Rule 9 */ else if (GET_CODE (src) == LO_SUM - && GET_CODE (XEXP (src, 1)) == CONST_INT) + && CONST_INT_P (XEXP (src, 1))) { cfa_temp.reg = REGNO (dest); cfa_temp.offset = INTVAL (XEXP (src, 1)); @@ -2109,7 +2356,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) case IOR: gcc_assert (REG_P (XEXP (src, 0)) && (unsigned) REGNO (XEXP (src, 0)) == cfa_temp.reg - && GET_CODE (XEXP (src, 1)) == CONST_INT); + && CONST_INT_P (XEXP (src, 1))); if ((unsigned) REGNO (dest) != cfa_temp.reg) cfa_temp.reg = REGNO (dest); @@ -2216,7 +2463,7 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) { int regno; - gcc_assert (GET_CODE (XEXP (XEXP (dest, 0), 1)) == CONST_INT + gcc_assert (CONST_INT_P (XEXP (XEXP (dest, 0), 1)) && REG_P (XEXP (XEXP (dest, 0), 0))); offset = INTVAL (XEXP (XEXP (dest, 0), 1)); if (GET_CODE (XEXP (dest, 0)) == MINUS) @@ -2373,7 +2620,8 @@ void dwarf2out_frame_debug (rtx insn, bool after_p) { const char *label; - rtx src; + rtx note, n; + bool handled_one = false; if (insn == NULL_RTX) { @@ -2417,16 +2665,155 @@ dwarf2out_frame_debug (rtx insn, bool after_p) return; } - label = dwarf2out_cfi_label (); - src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX); - if (src) - insn = XEXP (src, 0); - else - insn = PATTERN (insn); + label = dwarf2out_cfi_label (false); + + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) + switch (REG_NOTE_KIND (note)) + { + case REG_FRAME_RELATED_EXPR: + insn = XEXP (note, 0); + goto found; + + case REG_CFA_DEF_CFA: + dwarf2out_frame_debug_def_cfa (XEXP (note, 0), label); + handled_one = true; + break; + + case REG_CFA_ADJUST_CFA: + n = XEXP (note, 0); + if (n == NULL) + { + n = PATTERN (insn); + if (GET_CODE (n) == PARALLEL) + n = XVECEXP (n, 0, 0); + } + dwarf2out_frame_debug_adjust_cfa (n, label); + handled_one = true; + break; + + case REG_CFA_OFFSET: + n = XEXP (note, 0); + if (n == NULL) + n = single_set (insn); + dwarf2out_frame_debug_cfa_offset (n, label); + handled_one = true; + break; + + case REG_CFA_REGISTER: + n = XEXP (note, 0); + if (n == NULL) + { + n = PATTERN (insn); + if (GET_CODE (n) == PARALLEL) + n = XVECEXP (n, 0, 0); + } + dwarf2out_frame_debug_cfa_register (n, label); + handled_one = true; + break; + + case REG_CFA_RESTORE: + n = XEXP (note, 0); + if (n == NULL) + { + n = PATTERN (insn); + if (GET_CODE (n) == PARALLEL) + n = XVECEXP (n, 0, 0); + n = XEXP (n, 0); + } + dwarf2out_frame_debug_cfa_restore (n, label); + handled_one = true; + break; + + default: + break; + } + if (handled_one) + return; + insn = PATTERN (insn); + found: dwarf2out_frame_debug_expr (insn, label); } +/* 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 + NOTE_INSN_CFA_RESTORE_STATE at the appropriate place in the stream. */ + +void +dwarf2out_begin_epilogue (rtx insn) +{ + bool saw_frp = false; + rtx i; + + /* Scan forward to the return insn, noticing if there are possible + frame related insns. */ + for (i = NEXT_INSN (insn); i ; i = NEXT_INSN (i)) + { + if (!INSN_P (i)) + continue; + + /* Look for both regular and sibcalls to end the block. */ + if (returnjump_p (i)) + break; + if (CALL_P (i) && SIBLING_CALL_P (i)) + break; + + if (RTX_FRAME_RELATED_P (i)) + saw_frp = true; + } + + /* If the port doesn't emit epilogue unwind info, we don't need a + save/restore pair. */ + if (!saw_frp) + return; + + /* Otherwise, search forward to see if the return insn was the last + basic block of the function. If so, we don't need save/restore. */ + gcc_assert (i != NULL); + i = next_real_insn (i); + if (i == NULL) + return; + + /* Insert the restore before that next real insn in the stream, and before + a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be + properly nested. This should be after any label or alignment. This + will be pushed into the CFI stream by the function below. */ + while (1) + { + rtx p = PREV_INSN (i); + if (!NOTE_P (p)) + break; + if (NOTE_KIND (p) == NOTE_INSN_BASIC_BLOCK) + break; + i = p; + } + emit_note_before (NOTE_INSN_CFA_RESTORE_STATE, i); + + emit_cfa_remember = true; + + /* And emulate the state save. */ + gcc_assert (!cfa_remember.in_use); + cfa_remember = cfa; + cfa_remember.in_use = 1; +} + +/* A "subroutine" of dwarf2out_begin_epilogue. Emit the restore required. */ + +void +dwarf2out_frame_debug_restore_state (void) +{ + dw_cfi_ref cfi = new_cfi (); + const char *label = dwarf2out_cfi_label (false); + + cfi->dw_cfi_opc = DW_CFA_restore_state; + add_fde_cfi (label, cfi); + + gcc_assert (cfa_remember.in_use); + cfa = cfa_remember; + cfa_remember.in_use = 0; +} + #endif /* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */ @@ -2440,6 +2827,8 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi) { case DW_CFA_nop: case DW_CFA_GNU_window_save: + case DW_CFA_remember_state: + case DW_CFA_restore_state: return dw_cfi_oprnd_unused; case DW_CFA_set_loc: @@ -2454,6 +2843,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi) case DW_CFA_def_cfa: case DW_CFA_offset_extended_sf: case DW_CFA_def_cfa_sf: + case DW_CFA_restore: case DW_CFA_restore_extended: case DW_CFA_undefined: case DW_CFA_same_value: @@ -2557,16 +2947,6 @@ switch_to_eh_frame_section (void) } } -/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder. */ - -static HOST_WIDE_INT -div_data_align (HOST_WIDE_INT off) -{ - HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT; - gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off); - return r; -} - /* Output a Call Frame Information opcode and its operand(s). */ static void @@ -2731,42 +3111,42 @@ output_cfi_directive (dw_cfi_ref cfi) case DW_CFA_offset: case DW_CFA_offset_extended: case DW_CFA_offset_extended_sf: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); fprintf (asm_out_file, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n", r, cfi->dw_cfi_oprnd2.dw_cfi_offset); break; case DW_CFA_restore: case DW_CFA_restore_extended: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); fprintf (asm_out_file, "\t.cfi_restore %lu\n", r); break; case DW_CFA_undefined: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); fprintf (asm_out_file, "\t.cfi_undefined %lu\n", r); break; case DW_CFA_same_value: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); fprintf (asm_out_file, "\t.cfi_same_value %lu\n", r); break; case DW_CFA_def_cfa: case DW_CFA_def_cfa_sf: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); fprintf (asm_out_file, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n", r, cfi->dw_cfi_oprnd2.dw_cfi_offset); break; case DW_CFA_def_cfa_register: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); fprintf (asm_out_file, "\t.cfi_def_cfa_register %lu\n", r); break; case DW_CFA_register: - r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 0); - r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 0); + r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1); + r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 1); fprintf (asm_out_file, "\t.cfi_register %lu, %lu\n", r, r2); break; @@ -2777,6 +3157,13 @@ output_cfi_directive (dw_cfi_ref cfi) cfi->dw_cfi_oprnd1.dw_cfi_offset); break; + case DW_CFA_remember_state: + fprintf (asm_out_file, "\t.cfi_remember_state\n"); + break; + case DW_CFA_restore_state: + fprintf (asm_out_file, "\t.cfi_restore_state\n"); + break; + case DW_CFA_GNU_args_size: fprintf (asm_out_file, "\t.cfi_escape 0x%x,", DW_CFA_GNU_args_size); dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset); @@ -2820,6 +3207,7 @@ output_call_frame_info (int for_eh) int per_encoding = DW_EH_PE_absptr; int lsda_encoding = DW_EH_PE_absptr; int return_reg; + int dw_cie_version; /* Don't emit a CIE if there won't be any FDEs. */ if (fde_table_in_use == 0) @@ -2900,7 +3288,14 @@ output_call_frame_info (int for_eh) (for_eh ? 0 : DWARF_CIE_ID), "CIE Identifier Tag"); - dw2_asm_output_data (1, DW_CIE_VERSION, "CIE Version"); + /* Use the CIE version 3 for DWARF3; allow DWARF2 to continue to + use CIE version 1, unless that would produce incorrect results + due to overflowing the return register column. */ + return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh); + dw_cie_version = 1; + if (return_reg >= 256 || dwarf_version > 2) + dw_cie_version = 3; + dw2_asm_output_data (1, dw_cie_version, "CIE Version"); augmentation[0] = 0; augmentation_size = 0; @@ -2972,8 +3367,7 @@ output_call_frame_info (int for_eh) dw2_asm_output_data_sleb128 (DWARF_CIE_DATA_ALIGNMENT, "CIE Data Alignment Factor"); - return_reg = DWARF2_FRAME_REG_OUT (DWARF_FRAME_RETURN_COLUMN, for_eh); - if (DW_CIE_VERSION == 1) + if (dw_cie_version == 1) dw2_asm_output_data (1, return_reg, "CIE RA Column"); else dw2_asm_output_data_uleb128 (return_reg, "CIE RA Column"); @@ -3243,7 +3637,7 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED, prologue case, not the eh frame case. */ #ifdef DWARF2_DEBUGGING_INFO if (file) - dwarf2out_source_line (line, file); + dwarf2out_source_line (line, file, 0, true); #endif if (dwarf2out_do_cfi_asm ()) @@ -3301,6 +3695,10 @@ dwarf2out_end_epilogue (unsigned int line ATTRIBUTE_UNUSED, dw_fde_ref fde; char label[MAX_ARTIFICIAL_LABEL_BYTES]; +#ifdef DWARF2_DEBUGGING_INFO + last_var_location_insn = NULL_RTX; +#endif + if (dwarf2out_do_cfi_asm ()) fprintf (asm_out_file, "\t.cfi_endproc\n"); @@ -3388,24 +3786,18 @@ dwarf2out_switch_text_section (void) for emitting location expressions. */ /* Data about a single source file. */ -struct dwarf_file_data GTY(()) -{ +struct GTY(()) dwarf_file_data { const char * filename; int emitted_number; }; -/* We need some way to distinguish DW_OP_addr with a direct symbol - relocation from DW_OP_addr with a dtp-relative symbol relocation. */ -#define INTERNAL_DW_OP_tls_addr (0x100 + DW_OP_addr) - - typedef struct dw_val_struct *dw_val_ref; typedef struct die_struct *dw_die_ref; typedef const struct die_struct *const_dw_die_ref; typedef struct dw_loc_descr_struct *dw_loc_descr_ref; typedef struct dw_loc_list_struct *dw_loc_list_ref; -typedef struct deferred_locations_struct GTY(()) +typedef struct GTY(()) deferred_locations_struct { tree variable; dw_die_ref die; @@ -3444,8 +3836,7 @@ enum dw_val_class /* Describe a double word constant value. */ /* ??? Every instance of long_long in the code really means CONST_DOUBLE. */ -typedef struct dw_long_long_struct GTY(()) -{ +typedef struct GTY(()) dw_long_long_struct { unsigned long hi; unsigned long low; } @@ -3453,8 +3844,7 @@ dw_long_long_const; /* Describe a floating point constant value, or a vector constant value. */ -typedef struct dw_vec_struct GTY(()) -{ +typedef struct GTY(()) dw_vec_struct { unsigned char * GTY((length ("%h.length"))) array; unsigned length; unsigned elt_size; @@ -3464,8 +3854,7 @@ dw_vec_const; /* The dw_val_node describes an attribute's value, as it is represented internally. */ -typedef struct dw_val_struct GTY(()) -{ +typedef struct GTY(()) dw_val_struct { enum dw_val_class val_class; union dw_val_struct_union { @@ -3495,10 +3884,12 @@ dw_val_node; /* Locations in memory are described using a sequence of stack machine operations. */ -typedef struct dw_loc_descr_struct GTY(()) -{ +typedef struct GTY(()) dw_loc_descr_struct { dw_loc_descr_ref dw_loc_next; - enum dwarf_location_atom dw_loc_opc; + ENUM_BITFIELD (dwarf_location_atom) dw_loc_opc : 8; + /* Used to distinguish DW_OP_addr with a direct symbol relocation + from DW_OP_addr with a dtp-relative symbol relocation. */ + unsigned int dtprel : 1; int dw_loc_addr; dw_val_node dw_loc_oprnd1; dw_val_node dw_loc_oprnd2; @@ -3508,8 +3899,7 @@ dw_loc_descr_node; /* Location lists are ranges + location descriptions for that range, so you can track variables that are in different places over their entire life. */ -typedef struct dw_loc_list_struct GTY(()) -{ +typedef struct GTY(()) dw_loc_list_struct { dw_loc_list_ref dw_loc_next; const char *begin; /* Label for begin address of range */ const char *end; /* Label for end address of range */ @@ -3531,7 +3921,6 @@ dwarf_stack_op_name (unsigned int op) switch (op) { case DW_OP_addr: - case INTERNAL_DW_OP_tls_addr: return "DW_OP_addr"; case DW_OP_deref: return "DW_OP_deref"; @@ -3821,6 +4210,7 @@ dwarf_stack_op_name (unsigned int op) return "DW_OP_xderef_size"; case DW_OP_nop: return "DW_OP_nop"; + case DW_OP_push_object_address: return "DW_OP_push_object_address"; case DW_OP_call2: @@ -3829,10 +4219,20 @@ dwarf_stack_op_name (unsigned int op) return "DW_OP_call4"; case DW_OP_call_ref: return "DW_OP_call_ref"; + case DW_OP_form_tls_address: + return "DW_OP_form_tls_address"; + case DW_OP_call_frame_cfa: + return "DW_OP_call_frame_cfa"; + case DW_OP_bit_piece: + return "DW_OP_bit_piece"; + case DW_OP_GNU_push_tls_address: return "DW_OP_GNU_push_tls_address"; case DW_OP_GNU_uninit: return "DW_OP_GNU_uninit"; + case DW_OP_GNU_encoded_addr: + return "DW_OP_GNU_encoded_addr"; + default: return "OP_"; } @@ -3863,17 +4263,11 @@ new_loc_descr (enum dwarf_location_atom op, unsigned HOST_WIDE_INT oprnd1, static inline dw_loc_descr_ref new_reg_loc_descr (unsigned int reg, unsigned HOST_WIDE_INT offset) { - if (offset) - { - if (reg <= 31) - return new_loc_descr (DW_OP_breg0 + reg, offset, 0); - else - return new_loc_descr (DW_OP_bregx, reg, offset); - } - else if (reg <= 31) - return new_loc_descr (DW_OP_reg0 + reg, 0, 0); + if (reg <= 31) + return new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + reg), + offset, 0); else - return new_loc_descr (DW_OP_regx, reg, 0); + return new_loc_descr (DW_OP_bregx, reg, offset); } /* Add a location description term to a location description expression. */ @@ -3890,6 +4284,47 @@ add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr) *d = descr; } +/* Add a constant OFFSET to a location expression. */ + +static void +loc_descr_plus_const (dw_loc_descr_ref *list_head, HOST_WIDE_INT offset) +{ + dw_loc_descr_ref loc; + HOST_WIDE_INT *p; + + gcc_assert (*list_head != NULL); + + if (!offset) + return; + + /* Find the end of the chain. */ + for (loc = *list_head; loc->dw_loc_next != NULL; loc = loc->dw_loc_next) + ; + + p = NULL; + if (loc->dw_loc_opc == DW_OP_fbreg + || (loc->dw_loc_opc >= DW_OP_breg0 && loc->dw_loc_opc <= DW_OP_breg31)) + p = &loc->dw_loc_oprnd1.v.val_int; + else if (loc->dw_loc_opc == DW_OP_bregx) + p = &loc->dw_loc_oprnd2.v.val_int; + + /* If the last operation is fbreg, breg{0..31,x}, optimize by adjusting its + offset. Don't optimize if an signed integer overflow would happen. */ + if (p != NULL + && ((offset > 0 && *p <= INTTYPE_MAXIMUM (HOST_WIDE_INT) - offset) + || (offset < 0 && *p >= INTTYPE_MINIMUM (HOST_WIDE_INT) - offset))) + *p += offset; + + else if (offset > 0) + loc->dw_loc_next = new_loc_descr (DW_OP_plus_uconst, offset, 0); + + else + { + loc->dw_loc_next = int_loc_descriptor (offset); + add_loc_descr (&loc->dw_loc_next, new_loc_descr (DW_OP_plus, 0, 0)); + } +} + /* Return the size of a location descriptor. */ static unsigned long @@ -3900,7 +4335,6 @@ size_of_loc_descr (dw_loc_descr_ref loc) switch (loc->dw_loc_opc) { case DW_OP_addr: - case INTERNAL_DW_OP_tls_addr: size += DWARF2_ADDR_SIZE; break; case DW_OP_const1u: @@ -4041,9 +4475,6 @@ output_loc_operands (dw_loc_descr_ref loc) switch (loc->dw_loc_opc) { #ifdef DWARF2_DEBUGGING_INFO - case DW_OP_addr: - dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL); - break; case DW_OP_const2u: case DW_OP_const2s: dw2_asm_output_data (2, val1->v.val_int, NULL); @@ -4069,7 +4500,6 @@ output_loc_operands (dw_loc_descr_ref loc) } break; #else - case DW_OP_addr: case DW_OP_const2u: case DW_OP_const2s: case DW_OP_const4u: @@ -4152,16 +4582,27 @@ output_loc_operands (dw_loc_descr_ref loc) dw2_asm_output_data (1, val1->v.val_int, NULL); break; - case INTERNAL_DW_OP_tls_addr: - if (targetm.asm_out.output_dwarf_dtprel) + case DW_OP_addr: + if (loc->dtprel) { - targetm.asm_out.output_dwarf_dtprel (asm_out_file, - DWARF2_ADDR_SIZE, - val1->v.val_addr); - fputc ('\n', asm_out_file); + if (targetm.asm_out.output_dwarf_dtprel) + { + targetm.asm_out.output_dwarf_dtprel (asm_out_file, + DWARF2_ADDR_SIZE, + val1->v.val_addr); + fputc ('\n', asm_out_file); + } + else + gcc_unreachable (); } else - gcc_unreachable (); + { +#ifdef DWARF2_DEBUGGING_INFO + dw2_asm_output_addr_rtx (DWARF2_ADDR_SIZE, val1->v.val_addr, NULL); +#else + gcc_unreachable (); +#endif + } break; default: @@ -4295,9 +4736,6 @@ output_loc_operands_raw (dw_loc_descr_ref loc) dw2_asm_output_data_sleb128_raw (val2->v.val_int); break; - case INTERNAL_DW_OP_tls_addr: - gcc_unreachable (); - default: /* Other codes have no operands. */ break; @@ -4409,9 +4847,7 @@ build_cfa_aligned_loc (HOST_WIDE_INT offset, HOST_WIDE_INT alignment) head = new_reg_loc_descr (dwarf_fp, 0); add_loc_descr (&head, int_loc_descriptor (alignment)); add_loc_descr (&head, new_loc_descr (DW_OP_and, 0, 0)); - - add_loc_descr (&head, int_loc_descriptor (offset)); - add_loc_descr (&head, new_loc_descr (DW_OP_plus, 0, 0)); + loc_descr_plus_const (&head, offset); } else head = new_reg_loc_descr (dwarf_fp, offset); @@ -4549,6 +4985,7 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, static void dwarf2out_abstract_function (tree); static void dwarf2out_var_location (rtx); static void dwarf2out_begin_function (tree); +static void dwarf2out_set_name (tree, tree); /* The debug hooks structure. */ @@ -4582,6 +5019,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = debug_nothing_int, /* handle_pch */ dwarf2out_var_location, dwarf2out_switch_text_section, + dwarf2out_set_name, 1 /* start_end_main_source_file */ }; #endif @@ -4614,8 +5052,7 @@ typedef struct dw_ranges_by_label_struct *dw_ranges_by_label_ref; entry. The label gives the PC value associated with the line number entry. */ -typedef struct dw_line_info_struct GTY(()) -{ +typedef struct GTY(()) dw_line_info_struct { unsigned long dw_file_num; unsigned long dw_line_num; } @@ -4623,8 +5060,7 @@ dw_line_info_entry; /* Line information for functions in separate sections; each one gets its own sequence. */ -typedef struct dw_separate_line_info_struct GTY(()) -{ +typedef struct GTY(()) dw_separate_line_info_struct { unsigned long dw_file_num; unsigned long dw_line_num; unsigned long function; @@ -4635,8 +5071,7 @@ dw_separate_line_info_entry; a link to the next attribute in the chain, and an attribute value. Attributes are typically linked below the DIE they modify. */ -typedef struct dw_attr_struct GTY(()) -{ +typedef struct GTY(()) dw_attr_struct { enum dwarf_attribute dw_attr; dw_val_node dw_attr_val; } @@ -4649,8 +5084,7 @@ DEF_VEC_ALLOC_O(dw_attr_node,gc); The children of each node form a circular list linked by die_sib. die_child points to the node *before* the "first" child node. */ -typedef struct die_struct GTY((chain_circular ("%h.die_sib"))) -{ +typedef struct GTY((chain_circular ("%h.die_sib"))) die_struct { enum dwarf_tag die_tag; char *die_symbol; VEC(dw_attr_node,gc) * die_attr; @@ -4678,8 +5112,7 @@ die_node; /* The pubname structure */ -typedef struct pubname_struct GTY(()) -{ +typedef struct GTY(()) pubname_struct { dw_die_ref die; const char *name; } @@ -4688,22 +5121,19 @@ pubname_entry; DEF_VEC_O(pubname_entry); DEF_VEC_ALLOC_O(pubname_entry, gc); -struct dw_ranges_struct GTY(()) -{ +struct GTY(()) dw_ranges_struct { /* If this is positive, it's a block number, otherwise it's a bitwise-negated index into dw_ranges_by_label. */ int num; }; -struct dw_ranges_by_label_struct GTY(()) -{ +struct GTY(()) dw_ranges_by_label_struct { const char *begin; const char *end; }; /* The limbo die list structure. */ -typedef struct limbo_die_struct GTY(()) -{ +typedef struct GTY(()) limbo_die_struct { dw_die_ref die; tree created_for; struct limbo_die_struct *next; @@ -4796,6 +5226,11 @@ static GTY(()) dw_die_ref comp_unit_die; /* A list of DIEs with a NULL parent waiting to be relocated. */ static GTY(()) limbo_die_node *limbo_die_list; +/* A list of DIEs for which we may have to generate + DW_AT_MIPS_linkage_name once their DECL_ASSEMBLER_NAMEs are + set. */ +static GTY(()) limbo_die_node *deferred_asm_name; + /* Filenames referenced by this compilation unit. */ static GTY((param_is (struct dwarf_file_data))) htab_t file_table; @@ -4808,8 +5243,7 @@ static GTY ((param_is (struct die_struct))) htab_t decl_die_table; static GTY ((param_is (struct die_struct))) htab_t common_block_die_table; /* Node of the variable location list. */ -struct var_loc_node GTY ((chain_next ("%h.next"))) -{ +struct GTY ((chain_next ("%h.next"))) var_loc_node { rtx GTY (()) var_loc_note; const char * GTY (()) label; const char * GTY (()) section_label; @@ -4817,8 +5251,7 @@ struct var_loc_node GTY ((chain_next ("%h.next"))) }; /* Variable location list. */ -struct var_loc_list_def GTY (()) -{ +struct GTY (()) var_loc_list_def { struct var_loc_node * GTY (()) first; /* Do not mark the last element of the chained list because @@ -4975,7 +5408,7 @@ static hashval_t debug_str_do_hash (const void *); static int debug_str_eq (const void *, const void *); static void add_AT_string (dw_die_ref, enum dwarf_attribute, const char *); static inline const char *AT_string (dw_attr_ref); -static int AT_string_form (dw_attr_ref); +static enum dwarf_form AT_string_form (dw_attr_ref); static void add_AT_die_ref (dw_die_ref, enum dwarf_attribute, dw_die_ref); static void add_AT_specification (dw_die_ref, dw_die_ref); static inline dw_die_ref AT_ref (dw_attr_ref); @@ -5082,8 +5515,7 @@ static void output_line_info (void); static void output_file_names (void); static dw_die_ref base_type_die (tree); static int is_base_type (tree); -static bool is_subrange_type (const_tree); -static dw_die_ref subrange_type_die (tree, dw_die_ref); +static dw_die_ref subrange_type_die (tree, tree, tree, dw_die_ref); static dw_die_ref modified_type_die (tree, int, int, dw_die_ref); static int type_is_enum (const_tree); static unsigned int dbx_reg_number (const_rtx); @@ -5222,6 +5654,9 @@ static int maybe_emit_file (struct dwarf_file_data *fd); #ifndef DEBUG_PUBNAMES_SECTION #define DEBUG_PUBNAMES_SECTION ".debug_pubnames" #endif +#ifndef DEBUG_PUBTYPES_SECTION +#define DEBUG_PUBTYPES_SECTION ".debug_pubtypes" +#endif #ifndef DEBUG_STR_SECTION #define DEBUG_STR_SECTION ".debug_str" #endif @@ -5929,12 +6364,9 @@ debug_str_eq (const void *x1, const void *x2) (const char *)x2) == 0; } -/* Add a string attribute value to a DIE. */ - -static inline void -add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str) +static struct indirect_string_node * +find_AT_string (const char *str) { - dw_attr_node attr; struct indirect_string_node *node; void **slot; @@ -5955,6 +6387,18 @@ add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str) node = (struct indirect_string_node *) *slot; node->refcount++; + return node; +} + +/* Add a string attribute value to a DIE. */ + +static inline void +add_AT_string (dw_die_ref die, enum dwarf_attribute attr_kind, const char *str) +{ + dw_attr_node attr; + struct indirect_string_node *node; + + node = find_AT_string (str); attr.dw_attr = attr_kind; attr.dw_attr_val.val_class = dw_val_class_str; @@ -5972,7 +6416,7 @@ AT_string (dw_attr_ref a) /* Find out whether a string should be output inline in DIE or out-of-line in .debug_str section. */ -static int +static enum dwarf_form AT_string_form (dw_attr_ref a) { struct indirect_string_node *node; @@ -6841,7 +7285,10 @@ pop_compile_unit (dw_die_ref old_unit) static inline void loc_checksum (dw_loc_descr_ref loc, struct md5_ctx *ctx) { - CHECKSUM (loc->dw_loc_opc); + int tem; + + tem = (loc->dtprel << 8) | ((unsigned int) loc->dw_loc_opc); + CHECKSUM (tem); CHECKSUM (loc->dw_loc_oprnd1); CHECKSUM (loc->dw_loc_oprnd2); } @@ -7465,7 +7912,6 @@ build_abbrev_table (dw_die_ref die) && AT_ref (a)->die_mark == 0) { gcc_assert (AT_ref (a)->die_symbol); - set_AT_ref_external (a, 1); } @@ -7593,7 +8039,9 @@ size_of_die (dw_die_ref die) size += 1; break; case dw_val_class_die_ref: - if (AT_ref_external (a)) + /* In DWARF2, DW_FORM_ref_addr is sized by target address length, + whereas in DWARF3 it's always sized as an offset. */ + if (AT_ref_external (a) && dwarf_version == 2) size += DWARF2_ADDR_SIZE; else size += DWARF_OFFSET_SIZE; @@ -8122,10 +8570,17 @@ output_die (dw_die_ref die) if (AT_ref_external (a)) { char *sym = AT_ref (a)->die_symbol; + int size; gcc_assert (sym); - dw2_asm_output_offset (DWARF2_ADDR_SIZE, sym, debug_info_section, - "%s", name); + + /* 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 == 2) + size = DWARF2_ADDR_SIZE; + else + size = DWARF_OFFSET_SIZE; + dw2_asm_output_offset (size, sym, debug_info_section, "%s", name); } else { @@ -8204,7 +8659,7 @@ output_compilation_unit_header (void) dw2_asm_output_data (DWARF_OFFSET_SIZE, next_die_offset - DWARF_INITIAL_LENGTH_SIZE, "Length of Compilation Unit Info"); - dw2_asm_output_data (2, DWARF_VERSION, "DWARF version number"); + dw2_asm_output_data (2, dwarf_version, "DWARF version number"); dw2_asm_output_offset (DWARF_OFFSET_SIZE, abbrev_section_label, debug_abbrev_section, "Offset Into Abbrev. Section"); @@ -8285,7 +8740,6 @@ add_pubname_string (const char *str, dw_die_ref die) static void add_pubname (tree decl, dw_die_ref die) { - if (TREE_PUBLIC (decl)) add_pubname_string (dwarf2_name (decl, 1), die); } @@ -8345,7 +8799,8 @@ output_pubnames (VEC (pubname_entry, gc) * names) else dw2_asm_output_data (DWARF_OFFSET_SIZE, pubnames_length, "Length of Public Type Names Info"); - dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version"); + /* Version number for pubnames/pubtypes is still 2, even in DWARF3. */ + dw2_asm_output_data (2, 2, "DWARF Version"); dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, debug_info_section, "Offset of Compilation Unit Info"); @@ -8407,7 +8862,8 @@ output_aranges (void) "Initial length escape value indicating 64-bit DWARF extension"); dw2_asm_output_data (DWARF_OFFSET_SIZE, aranges_length, "Length of Address Ranges Info"); - dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version"); + /* Version number for aranges is still 2, even in DWARF3. */ + dw2_asm_output_data (2, 2, "DWARF Version"); dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, debug_info_section, "Offset of Compilation Unit Info"); @@ -8952,7 +9408,7 @@ output_line_info (void) "Length of Source Line Info"); ASM_OUTPUT_LABEL (asm_out_file, l1); - dw2_asm_output_data (2, DWARF_VERSION, "DWARF Version"); + dw2_asm_output_data (2, dwarf_version, "DWARF Version"); dw2_asm_output_delta (DWARF_OFFSET_SIZE, p2, p1, "Prolog Length"); ASM_OUTPUT_LABEL (asm_out_file, p1); @@ -9251,6 +9707,11 @@ base_type_die (tree type) if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE) return 0; + /* If this is a subtype that should not be emitted as a subrange type, + use the base type. See subrange_type_for_debug_p. */ + if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE) + type = TREE_TYPE (type); + switch (TREE_CODE (type)) { case INTEGER_TYPE: @@ -9370,67 +9831,11 @@ simple_type_size_in_bits (const_tree type) return TYPE_ALIGN (type); } -/* Return true if the debug information for the given type should be - emitted as a subrange type. */ - -static inline bool -is_subrange_type (const_tree type) -{ - tree subtype = TREE_TYPE (type); - - /* Subrange types are identified by the fact that they are integer - types, and that they have a subtype which is either an integer type - or an enumeral type. */ - - if (TREE_CODE (type) != INTEGER_TYPE - || subtype == NULL_TREE) - return false; - - if (TREE_CODE (subtype) != INTEGER_TYPE - && TREE_CODE (subtype) != ENUMERAL_TYPE - && TREE_CODE (subtype) != BOOLEAN_TYPE) - return false; - - if (TREE_CODE (type) == TREE_CODE (subtype) - && int_size_in_bytes (type) == int_size_in_bytes (subtype) - && TYPE_MIN_VALUE (type) != NULL - && TYPE_MIN_VALUE (subtype) != NULL - && tree_int_cst_equal (TYPE_MIN_VALUE (type), TYPE_MIN_VALUE (subtype)) - && TYPE_MAX_VALUE (type) != NULL - && TYPE_MAX_VALUE (subtype) != NULL - && tree_int_cst_equal (TYPE_MAX_VALUE (type), TYPE_MAX_VALUE (subtype))) - { - /* The type and its subtype have the same representation. If in - addition the two types also have the same name, then the given - type is not a subrange type, but rather a plain base type. */ - /* FIXME: brobecker/2004-03-22: - Sizetype INTEGER_CSTs nodes are canonicalized. It should - therefore be sufficient to check the TYPE_SIZE node pointers - rather than checking the actual size. Unfortunately, we have - found some cases, such as in the Ada "integer" type, where - this is not the case. Until this problem is solved, we need to - keep checking the actual size. */ - tree type_name = TYPE_NAME (type); - tree subtype_name = TYPE_NAME (subtype); - - if (type_name != NULL && TREE_CODE (type_name) == TYPE_DECL) - type_name = DECL_NAME (type_name); - - if (subtype_name != NULL && TREE_CODE (subtype_name) == TYPE_DECL) - subtype_name = DECL_NAME (subtype_name); - - if (type_name == subtype_name) - return false; - } - - return true; -} - /* Given a pointer to a tree node for a subrange type, return a pointer to a DIE that describes the given type. */ static dw_die_ref -subrange_type_die (tree type, dw_die_ref context_die) +subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die) { dw_die_ref subrange_die; const HOST_WIDE_INT size_in_bytes = int_size_in_bytes (type); @@ -9447,12 +9852,10 @@ subrange_type_die (tree type, dw_die_ref context_die) add_AT_unsigned (subrange_die, DW_AT_byte_size, size_in_bytes); } - if (TYPE_MIN_VALUE (type) != NULL) - add_bound_info (subrange_die, DW_AT_lower_bound, - TYPE_MIN_VALUE (type)); - if (TYPE_MAX_VALUE (type) != NULL) - add_bound_info (subrange_die, DW_AT_upper_bound, - TYPE_MAX_VALUE (type)); + if (low) + add_bound_info (subrange_die, DW_AT_lower_bound, low); + if (high) + add_bound_info (subrange_die, DW_AT_upper_bound, high); return subrange_die; } @@ -9469,7 +9872,7 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, dw_die_ref sub_die = NULL; tree item_type = NULL; tree qualified_type; - tree name; + tree name, low, high; if (code == ERROR_MARK) return NULL; @@ -9539,9 +9942,11 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, simple_type_size_in_bits (type) / BITS_PER_UNIT); item_type = TREE_TYPE (type); } - else if (is_subrange_type (type)) + else if (code == INTEGER_TYPE + && TREE_TYPE (type) != NULL_TREE + && subrange_type_for_debug_p (type, &low, &high)) { - mod_type_die = subrange_type_die (type, context_die); + mod_type_die = subrange_type_die (type, low, high, context_die); item_type = TREE_TYPE (type); } else if (is_base_type (type)) @@ -9673,7 +10078,13 @@ reg_loc_descriptor (rtx rtl, enum var_init_status initialized) static dw_loc_descr_ref one_reg_loc_descriptor (unsigned int regno, enum var_init_status initialized) { - dw_loc_descr_ref reg_loc_descr = new_reg_loc_descr (regno, 0); + dw_loc_descr_ref reg_loc_descr; + + if (regno <= 31) + reg_loc_descr + = new_loc_descr ((enum dwarf_location_atom) (DW_OP_reg0 + regno), 0, 0); + else + reg_loc_descr = new_loc_descr (DW_OP_regx, regno, 0); if (initialized == VAR_INIT_STATUS_UNINITIALIZED) add_loc_descr (®_loc_descr, new_loc_descr (DW_OP_GNU_uninit, 0, 0)); @@ -9762,7 +10173,7 @@ int_loc_descriptor (HOST_WIDE_INT i) if (i >= 0) { if (i <= 31) - op = DW_OP_lit0 + i; + op = (enum dwarf_location_atom) (DW_OP_lit0 + i); else if (i <= 0xff) op = DW_OP_const1u; else if (i <= 0xffff) @@ -9855,7 +10266,8 @@ based_loc_descr (rtx reg, HOST_WIDE_INT offset, regno = dbx_reg_number (reg); if (regno <= 31) - result = new_loc_descr (DW_OP_breg0 + regno, offset, 0); + result = new_loc_descr ((enum dwarf_location_atom) (DW_OP_breg0 + regno), + offset, 0); else result = new_loc_descr (DW_OP_bregx, regno, offset); @@ -9873,7 +10285,7 @@ is_based_loc (const_rtx rtl) return (GET_CODE (rtl) == PLUS && ((REG_P (XEXP (rtl, 0)) && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER - && GET_CODE (XEXP (rtl, 1)) == CONST_INT))); + && CONST_INT_P (XEXP (rtl, 1))))); } /* Return a descriptor that describes the concatenation of N locations @@ -9913,7 +10325,7 @@ static dw_loc_descr_ref tls_mem_loc_descriptor (rtx mem) { tree base; - dw_loc_descr_ref loc_result, loc_result2; + dw_loc_descr_ref loc_result; if (MEM_EXPR (mem) == NULL_TREE || MEM_OFFSET (mem) == NULL_RTX) return NULL; @@ -9929,21 +10341,7 @@ tls_mem_loc_descriptor (rtx mem) return NULL; if (INTVAL (MEM_OFFSET (mem))) - { - if (INTVAL (MEM_OFFSET (mem)) >= 0) - add_loc_descr (&loc_result, - new_loc_descr (DW_OP_plus_uconst, - INTVAL (MEM_OFFSET (mem)), 0)); - else - { - loc_result2 = mem_loc_descriptor (MEM_OFFSET (mem), GET_MODE (mem), - VAR_INIT_STATUS_INITIALIZED); - if (loc_result2 == 0) - return NULL; - add_loc_descr (&loc_result, loc_result2); - add_loc_descr (&loc_result, new_loc_descr (DW_OP_plus, 0, 0)); - } - } + loc_descr_plus_const (&loc_result, INTVAL (MEM_OFFSET (mem))); return loc_result; } @@ -10108,11 +10506,8 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, if (mem_loc_result == 0) break; - if (GET_CODE (XEXP (rtl, 1)) == CONST_INT - && INTVAL (XEXP (rtl, 1)) >= 0) - add_loc_descr (&mem_loc_result, - new_loc_descr (DW_OP_plus_uconst, - INTVAL (XEXP (rtl, 1)), 0)); + if (CONST_INT_P (XEXP (rtl, 1))) + loc_descr_plus_const (&mem_loc_result, INTVAL (XEXP (rtl, 1))); else { dw_loc_descr_ref mem_loc_result2 @@ -10383,8 +10778,9 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (DECL_THREAD_LOCAL_P (loc)) { rtx rtl; - unsigned first_op; - unsigned second_op; + enum dwarf_location_atom first_op; + enum dwarf_location_atom second_op; + bool dtprel = false; if (targetm.have_tls) { @@ -10398,7 +10794,8 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) module. */ if (DECL_EXTERNAL (loc) && !targetm.binds_local_p (loc)) return 0; - first_op = INTERNAL_DW_OP_tls_addr; + first_op = DW_OP_addr; + dtprel = true; second_op = DW_OP_GNU_push_tls_address; } else @@ -10423,6 +10820,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) ret = new_loc_descr (first_op, 0, 0); ret->dw_loc_oprnd1.val_class = dw_val_class_addr; ret->dw_loc_oprnd1.v.val_addr = rtl; + ret->dtprel = dtprel; ret1 = new_loc_descr (second_op, 0, 0); add_loc_descr (&ret, ret1); @@ -10445,7 +10843,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (rtl == NULL_RTX) return 0; - else if (GET_CODE (rtl) == CONST_INT) + else if (CONST_INT_P (rtl)) { HOST_WIDE_INT val = INTVAL (rtl); if (TYPE_UNSIGNED (TREE_TYPE (loc))) @@ -10526,13 +10924,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) } bytepos = bitpos / BITS_PER_UNIT; - if (bytepos > 0) - add_loc_descr (&ret, new_loc_descr (DW_OP_plus_uconst, bytepos, 0)); - else if (bytepos < 0) - { - add_loc_descr (&ret, int_loc_descriptor (bytepos)); - add_loc_descr (&ret, new_loc_descr (DW_OP_plus, 0, 0)); - } + loc_descr_plus_const (&ret, bytepos); have_address = 1; break; @@ -10616,11 +11008,7 @@ loc_descriptor_from_tree_1 (tree loc, int want_address) if (ret == 0) return 0; - add_loc_descr (&ret, - new_loc_descr (DW_OP_plus_uconst, - tree_low_cst (TREE_OPERAND (loc, 1), - 0), - 0)); + loc_descr_plus_const (&ret, tree_low_cst (TREE_OPERAND (loc, 1), 0)); break; } @@ -10889,21 +11277,22 @@ field_byte_offset (const_tree decl) unsigned HOST_WIDE_INT type_size_in_bits; type = field_type (decl); + type_size_in_bits = simple_type_size_in_bits (type); + type_align_in_bits = simple_type_align_in_bits (type); + field_size_tree = DECL_SIZE (decl); /* The size could be unspecified if there was an error, or for a flexible array member. */ - if (! field_size_tree) + if (!field_size_tree) field_size_tree = bitsize_zero_node; - /* If we don't know the size of the field, pretend it's a full word. */ + /* If the size of the field is not constant, use the type size. */ if (host_integerp (field_size_tree, 1)) field_size_in_bits = tree_low_cst (field_size_tree, 1); else - field_size_in_bits = BITS_PER_WORD; + field_size_in_bits = type_size_in_bits; - type_size_in_bits = simple_type_size_in_bits (type); - type_align_in_bits = simple_type_align_in_bits (type); decl_align_in_bits = simple_decl_align_in_bits (decl); /* The GCC front-end doesn't make any attempt to keep track of the @@ -11709,10 +12098,37 @@ loc_by_reference (dw_loc_descr_ref loc, tree decl) if (loc == NULL) return NULL; - if ((TREE_CODE (decl) != PARM_DECL && TREE_CODE (decl) != RESULT_DECL) + if ((TREE_CODE (decl) != PARM_DECL + && TREE_CODE (decl) != RESULT_DECL + && TREE_CODE (decl) != VAR_DECL) || !DECL_BY_REFERENCE (decl)) return loc; + /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead + change it into corresponding DW_OP_breg{0...31,x} 0. Then the + location expression is considered to be address of a memory location, + rather than the register itself. */ + if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31) + || loc->dw_loc_opc == DW_OP_regx) + && (loc->dw_loc_next == NULL + || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit + && loc->dw_loc_next->dw_loc_next == NULL))) + { + if (loc->dw_loc_opc == DW_OP_regx) + { + loc->dw_loc_opc = DW_OP_bregx; + loc->dw_loc_oprnd2.v.val_int = 0; + } + else + { + loc->dw_loc_opc + = (enum dwarf_location_atom) + (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0)); + loc->dw_loc_oprnd1.v.val_int = 0; + } + return loc; + } + size = int_size_in_bytes (TREE_TYPE (decl)); if (size > DWARF2_ADDR_SIZE || size == -1) return 0; @@ -12078,6 +12494,7 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) dw_cfi_ref cfi; dw_cfa_location last_cfa, next_cfa; const char *start_label, *last_label, *section; + dw_cfa_location remember; fde = current_fde (); gcc_assert (fde != NULL); @@ -12086,17 +12503,16 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) list_tail = &list; list = NULL; + memset (&next_cfa, 0, sizeof (next_cfa)); next_cfa.reg = INVALID_REGNUM; - next_cfa.offset = 0; - next_cfa.indirect = 0; - next_cfa.base_offset = 0; + remember = next_cfa; start_label = fde->dw_fde_begin; /* ??? Bald assumption that the CIE opcode list does not contain advance opcodes. */ for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next) - lookup_cfa_1 (cfi, &next_cfa); + lookup_cfa_1 (cfi, &next_cfa, &remember); last_cfa = next_cfa; last_label = start_label; @@ -12123,14 +12539,10 @@ convert_cfa_to_fb_loc_list (HOST_WIDE_INT offset) case DW_CFA_advance_loc: /* The encoding is complex enough that we should never emit this. */ - case DW_CFA_remember_state: - case DW_CFA_restore_state: - /* We don't handle these two in this function. It would be possible - if it were to be required. */ gcc_unreachable (); default: - lookup_cfa_1 (cfi, &next_cfa); + lookup_cfa_1 (cfi, &next_cfa, &remember); break; } @@ -12570,12 +12982,25 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl) if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) && TREE_PUBLIC (decl) - && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !DECL_ABSTRACT (decl) && !(TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)) && !is_fortran ()) - add_AT_string (die, DW_AT_MIPS_linkage_name, - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); + { + /* Defer until we have an assembler name set. */ + if (!DECL_ASSEMBLER_NAME_SET_P (decl)) + { + limbo_die_node *asm_name; + + asm_name = GGC_CNEW (limbo_die_node); + asm_name->die = die; + asm_name->created_for = decl; + asm_name->next = deferred_asm_name; + deferred_asm_name = asm_name; + } + else if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) + add_AT_string (die, DW_AT_MIPS_linkage_name, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); + } } #ifdef VMS_DEBUGGING_INFO @@ -12744,7 +13169,8 @@ add_calling_convention_attribute (dw_die_ref subr_die, tree decl) { enum dwarf_calling_convention value = DW_CC_normal; - value = targetm.dwarf_calling_convention (TREE_TYPE (decl)); + value = ((enum dwarf_calling_convention) + targetm.dwarf_calling_convention (TREE_TYPE (decl))); /* DWARF doesn't provide a way to identify a program's source-level entry point. DW_AT_calling_convention attributes are only meant @@ -12999,10 +13425,7 @@ descr_info_loc (tree val, tree base_decl) loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl); if (!loc) break; - add_loc_descr (&loc, - new_loc_descr (DW_OP_plus_uconst, - tree_low_cst (TREE_OPERAND (val, 1), - 1), 0)); + loc_descr_plus_const (&loc, tree_low_cst (TREE_OPERAND (val, 1), 0)); } else { @@ -13436,6 +13859,7 @@ dwarf2out_abstract_function (tree decl) /* Make sure we have the actual abstract inline, not a clone. */ decl = DECL_ORIGIN (decl); + htab_empty (decl_loc_table); old_die = lookup_decl_die (decl); if (old_die && get_AT (old_die, DW_AT_inline)) @@ -13710,17 +14134,19 @@ gen_subprogram_die (tree decl, dw_die_ref context_die) (3) We can at least reuse the code inspection and interpretation code that determines the CFA position at various points in the function. */ - /* ??? Use some command-line or configury switch to enable the use - of dwarf3 DW_OP_call_frame_cfa. At present there are no dwarf - consumers that understand it; fall back to "pure" dwarf2 and - convert the CFA data into a location list. */ - { - dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset); - if (list->dw_loc_next) - add_AT_loc_list (subr_die, DW_AT_frame_base, list); - else - add_AT_loc (subr_die, DW_AT_frame_base, list->expr); - } + if (dwarf_version >= 3) + { + dw_loc_descr_ref op = new_loc_descr (DW_OP_call_frame_cfa, 0, 0); + add_AT_loc (subr_die, DW_AT_frame_base, op); + } + else + { + dw_loc_list_ref list = convert_cfa_to_fb_loc_list (cfa_fb_offset); + if (list->dw_loc_next) + add_AT_loc_list (subr_die, DW_AT_frame_base, list); + else + add_AT_loc (subr_die, DW_AT_frame_base, list->expr); + } /* Compute a displacement from the "steady-state frame pointer" to the CFA. The former is what all stack slots and argument slots @@ -13918,9 +14344,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) loc->dw_loc_oprnd1.v.val_addr = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off); else - add_loc_descr (&loc, - new_loc_descr (DW_OP_plus_uconst, - off, 0)); + loc_descr_plus_const (&loc, off); } add_AT_loc (var_die, DW_AT_location, loc); remove_AT (var_die, DW_AT_declaration); @@ -13983,8 +14407,7 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) loc->dw_loc_oprnd1.v.val_addr = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off); else - add_loc_descr (&loc, new_loc_descr (DW_OP_plus_uconst, - off, 0)); + loc_descr_plus_const (&loc, off); } add_AT_loc (var_die, DW_AT_location, loc); } @@ -14050,7 +14473,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die) add_name_and_src_coords_attributes (var_die, decl); if ((TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == RESULT_DECL) + || TREE_CODE (decl) == RESULT_DECL + || TREE_CODE (decl) == VAR_DECL) && DECL_BY_REFERENCE (decl)) add_type_attribute (var_die, TREE_TYPE (type), 0, 0, context_die); else @@ -14668,6 +15092,12 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die, /* Prevent broken recursion; we can't hand off to the same type. */ gcc_assert (DECL_ORIGINAL_TYPE (TYPE_NAME (type)) != type); + /* Use the DIE of the containing namespace as the parent DIE of + the type description DIE we want to generate. */ + if (DECL_CONTEXT (TYPE_NAME (type)) + && TREE_CODE (DECL_CONTEXT (TYPE_NAME (type))) == NAMESPACE_DECL) + context_die = lookup_decl_die (DECL_CONTEXT (TYPE_NAME (type))); + TREE_ASM_WRITTEN (type) = 1; gen_decl_die (TYPE_NAME (type), NULL, context_die); return; @@ -15298,7 +15728,8 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die) /* Output any DIEs that are needed to specify the type of this data object. */ - if (TREE_CODE (decl_or_origin) == RESULT_DECL + if ((TREE_CODE (decl_or_origin) == RESULT_DECL + || TREE_CODE (decl_or_origin) == VAR_DECL) && DECL_BY_REFERENCE (decl_or_origin)) gen_type_die (TREE_TYPE (TREE_TYPE (decl_or_origin)), context_die); else @@ -15763,6 +16194,32 @@ maybe_emit_file (struct dwarf_file_data * fd) return fd->emitted_number; } +/* Replace DW_AT_name for the decl with name. */ + +static void +dwarf2out_set_name (tree decl, tree name) +{ + dw_die_ref die; + dw_attr_ref attr; + + die = TYPE_SYMTAB_DIE (decl); + if (!die) + return; + + attr = get_AT (die, DW_AT_name); + if (attr) + { + struct indirect_string_node *node; + + node = find_AT_string (dwarf2_name (name, 0)); + /* replace the string. */ + attr->dw_attr_val.v.val_str = node; + } + + else + add_name_attribute (die, dwarf2_name (name, 0)); +} + /* 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. */ @@ -15772,26 +16229,27 @@ dwarf2out_var_location (rtx loc_note) { char loclabel[MAX_ARTIFICIAL_LABEL_BYTES]; struct var_loc_node *newloc; - rtx prev_insn; - static rtx last_insn; + rtx next_real; static const char *last_label; + static bool last_in_cold_section_p; tree decl; if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note))) return; - prev_insn = PREV_INSN (loc_note); + + 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) + return; newloc = GGC_CNEW (struct var_loc_node); - /* If the insn we processed last time is the previous insn - and it is also a var location note, use the label we emitted - last time. */ - if (last_insn != NULL_RTX - && last_insn == prev_insn - && NOTE_P (prev_insn) - && NOTE_KIND (prev_insn) == NOTE_INSN_VAR_LOCATION) - { - newloc->label = last_label; - } + /* If there were no real insns between note we processed last time + and this note, use the label we emitted last time. */ + if (last_var_location_insn != NULL_RTX + && last_var_location_insn == next_real + && last_in_cold_section_p == in_cold_section_p) + newloc->label = last_label; else { ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", loclabel_num); @@ -15807,8 +16265,9 @@ dwarf2out_var_location (rtx loc_note) else newloc->section_label = text_section_label; - last_insn = loc_note; + last_var_location_insn = next_real; last_label = newloc->label; + last_in_cold_section_p = in_cold_section_p; decl = NOTE_VAR_LOCATION_DECL (loc_note); add_var_loc_to_decl (decl, newloc); } @@ -15834,8 +16293,11 @@ dwarf2out_begin_function (tree fun) 'line_info_table' for later output of the .debug_line section. */ static void -dwarf2out_source_line (unsigned int line, const char *filename) +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) { @@ -15851,7 +16313,15 @@ dwarf2out_source_line (unsigned int line, const char *filename) if (DWARF2_ASM_LINE_DEBUG_INFO) { /* Emit the .loc directive understood by GNU as. */ - fprintf (asm_out_file, "\t.loc %d %d 0\n", file_num, line); + 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); /* Indicate that line number info exists. */ line_info_table_in_use++; @@ -16052,10 +16522,8 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) SECTION_DEBUG, NULL); debug_pubnames_section = get_section (DEBUG_PUBNAMES_SECTION, SECTION_DEBUG, NULL); -#ifdef DEBUG_PUBTYPES_SECTION debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION, SECTION_DEBUG, NULL); -#endif debug_str_section = get_section (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); debug_ranges_section = get_section (DEBUG_RANGES_SECTION, @@ -16445,6 +16913,36 @@ file_table_relative_p (void ** slot, void *param) return 1; } +/* Move a DW_AT_MIPS_linkage_name attribute just added to dw_die_ref + to the location it would have been added, should we know its + DECL_ASSEMBLER_NAME when we added other attributes. This will + probably improve compactness of debug info, removing equivalent + abbrevs, and hide any differences caused by deferring the + computation of the assembler name, triggered by e.g. PCH. */ + +static inline void +move_linkage_attr (dw_die_ref die) +{ + unsigned ix = VEC_length (dw_attr_node, die->die_attr); + dw_attr_node linkage = *VEC_index (dw_attr_node, die->die_attr, ix - 1); + + gcc_assert (linkage.dw_attr == DW_AT_MIPS_linkage_name); + + while (--ix > 0) + { + dw_attr_node *prev = VEC_index (dw_attr_node, die->die_attr, ix - 1); + + if (prev->dw_attr == DW_AT_decl_line || prev->dw_attr == DW_AT_name) + break; + } + + if (ix != VEC_length (dw_attr_node, die->die_attr) - 1) + { + VEC_pop (dw_attr_node, die->die_attr); + VEC_quick_insert (dw_attr_node, die->die_attr, ix, &linkage); + } +} + /* Output stuff that dwarf requires at the end of every file, and generate the DWARF-2 debugging info. */ @@ -16533,6 +17031,19 @@ dwarf2out_finish (const char *filename) limbo_die_list = NULL; + for (node = deferred_asm_name; node; node = node->next) + { + tree decl = node->created_for; + if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)) + { + add_AT_string (node->die, DW_AT_MIPS_linkage_name, + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); + move_linkage_attr (node->die); + } + } + + deferred_asm_name = NULL; + /* Walk through the list of incomplete types again, trying once more to emit full debugging info for them. */ retry_incomplete_types (); @@ -16644,14 +17155,15 @@ dwarf2out_finish (const char *filename) output_pubnames (pubname_table); } -#ifdef DEBUG_PUBTYPES_SECTION /* Output public types table if necessary. */ + /* ??? Only defined by DWARF3, but emitted by Darwin for DWARF2. + It shouldn't hurt to emit it always, since pure DWARF2 consumers + simply won't look for the section. */ if (!VEC_empty (pubname_entry, pubtype_table)) { switch_to_section (debug_pubtypes_section); output_pubnames (pubtype_table); } -#endif /* 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. */ @@ -16696,7 +17208,36 @@ dwarf2out_finish (const char *filename) #else /* This should never be used, but its address is needed for comparisons. */ -const struct gcc_debug_hooks dwarf2_debug_hooks; +const struct gcc_debug_hooks dwarf2_debug_hooks = +{ + 0, /* init */ + 0, /* finish */ + 0, /* define */ + 0, /* undef */ + 0, /* start_source_file */ + 0, /* end_source_file */ + 0, /* begin_block */ + 0, /* end_block */ + 0, /* ignore_block */ + 0, /* source_line */ + 0, /* begin_prologue */ + 0, /* end_prologue */ + 0, /* end_epilogue */ + 0, /* begin_function */ + 0, /* end_function */ + 0, /* function_decl */ + 0, /* global_decl */ + 0, /* type_decl */ + 0, /* imported_module_or_decl */ + 0, /* deferred_inline_function */ + 0, /* outlining_inline_function */ + 0, /* label */ + 0, /* handle_pch */ + 0, /* var_location */ + 0, /* switch_text_section */ + 0, /* set_name */ + 0 /* start_end_main_source_file */ +}; #endif /* DWARF2_DEBUGGING_INFO */