#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
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;
}
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)")))
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
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;
unsigned stack_realign : 1;
/* Whether dynamic realign argument pointer register has been saved. */
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
+ cold_text_section. */
+ unsigned cold_in_std_section : 1;
}
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))
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;
};
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
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
/* 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:
*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
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, "<do not output>") == 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
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)
/* 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)
{
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;
}
{
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. */
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;
}
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;
/* 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;
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))) */
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;
}
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);
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
if (offset == 0)
return;
- label = dwarf2out_cfi_label ();
+ label = dwarf2out_cfi_label (false);
dwarf2out_args_size_adjust (offset, 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;
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;
};
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.
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);
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;
/* 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. */
/* 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));
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);
{
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)
dwarf2out_frame_debug (rtx insn, bool after_p)
{
const char *label;
- rtx src;
+ rtx note, n;
+ bool handled_one = false;
if (insn == NULL_RTX)
{
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 (GET_CODE (PATTERN (i)) == SEQUENCE)
+ {
+ int idx;
+ rtx seq = PATTERN (i);
+
+ if (returnjump_p (XVECEXP (seq, 0, 0)))
+ break;
+ if (CALL_P (XVECEXP (seq, 0, 0))
+ && SIBLING_CALL_P (XVECEXP (seq, 0, 0)))
+ break;
+
+ for (idx = 0; idx < XVECLEN (seq, 0); idx++)
+ if (RTX_FRAME_RELATED_P (XVECEXP (seq, 0, idx)))
+ saw_frp = true;
+ }
+
+ 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. */
{
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:
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:
}
}
-/* 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
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;
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);
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)
(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;
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");
char label[MAX_ARTIFICIAL_LABEL_BYTES];
char * dup_label;
dw_fde_ref fde;
+ section *fnsec;
current_function_func_begin_label = NULL;
return;
#endif
- switch_to_section (function_section (current_function_decl));
+ fnsec = function_section (current_function_decl);
+ switch_to_section (fnsec);
ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, FUNC_BEGIN_LABEL,
fde->all_throwers_are_sibcalls = crtl->all_throwers_are_sibcalls;
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;
+ }
args_size = old_args_size = 0;
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 ())
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");
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;
/* 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;
}
/* 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;
/* 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
{
/* 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;
/* 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 */
switch (op)
{
case DW_OP_addr:
- case INTERNAL_DW_OP_tls_addr:
return "DW_OP_addr";
case DW_OP_deref:
return "DW_OP_deref";
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:
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_<unknown>";
}
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. */
*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
switch (loc->dw_loc_opc)
{
case DW_OP_addr:
- case INTERNAL_DW_OP_tls_addr:
size += DWARF2_ADDR_SIZE;
break;
case DW_OP_const1u:
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);
}
break;
#else
- case DW_OP_addr:
case DW_OP_const2u:
case DW_OP_const2s:
case DW_OP_const4u:
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:
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;
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);
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. */
debug_nothing_int, /* handle_pch */
dwarf2out_var_location,
dwarf2out_switch_text_section,
+ dwarf2out_set_name,
1 /* start_end_main_source_file */
};
#endif
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;
}
/* 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;
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;
}
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;
/* The pubname structure */
-typedef struct pubname_struct GTY(())
-{
+typedef struct GTY(()) pubname_struct {
dw_die_ref die;
const char *name;
}
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;
/* 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;
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;
};
/* 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
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);
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);
#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
(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;
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;
/* 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;
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);
}
&& AT_ref (a)->die_mark == 0)
{
gcc_assert (AT_ref (a)->die_symbol);
-
set_AT_ref_external (a, 1);
}
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;
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
{
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");
static void
add_pubname (tree decl, dw_die_ref die)
{
-
if (TREE_PUBLIC (decl))
add_pubname_string (dwarf2_name (decl, 1), die);
}
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");
"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");
"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);
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:
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);
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;
}
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;
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))
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));
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)
is aligned without drap, use stack pointer + offset to
access stack variables. */
if (crtl->stack_realign_tried
- && cfa.reg == HARD_FRAME_POINTER_REGNUM
&& reg == frame_pointer_rtx)
{
int base_reg
- = DWARF_FRAME_REGNUM (cfa.indirect
+ = DWARF_FRAME_REGNUM ((fde && fde->drap_reg != INVALID_REGNUM)
? HARD_FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM);
return new_reg_loc_descr (base_reg, 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);
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
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;
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;
}
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
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)
{
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
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);
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)))
}
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;
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;
}
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
if (! loc_descr)
{
- enum dwarf_location_atom op;
-
- /* The DWARF2 standard says that we should assume that the structure
- address is already on the stack, so we can specify a structure field
- address by using DW_OP_plus_uconst. */
-
+ if (dwarf_version > 2)
+ {
+ /* Don't need to output a location expression, just the constant. */
+ add_AT_int (die, DW_AT_data_member_location, offset);
+ return;
+ }
+ else
+ {
+ enum dwarf_location_atom op;
+
+ /* The DWARF2 standard says that we should assume that the structure
+ address is already on the stack, so we can specify a structure
+ field address by using DW_OP_plus_uconst. */
+
#ifdef MIPS_DEBUGGING_INFO
- /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
- operator correctly. It works only if we leave the offset on the
- stack. */
- op = DW_OP_constu;
+ /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst
+ operator correctly. It works only if we leave the offset on the
+ stack. */
+ op = DW_OP_constu;
#else
- op = DW_OP_plus_uconst;
+ op = DW_OP_plus_uconst;
#endif
-
- loc_descr = new_loc_descr (op, offset, 0);
+
+ loc_descr = new_loc_descr (op, offset, 0);
+ }
}
add_AT_loc (die, DW_AT_data_member_location, loc_descr);
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;
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);
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;
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;
}
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
{
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
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
{
add_AT_flag (parm_die, DW_AT_artificial, 1);
}
- if (node)
+ if (node && node != origin)
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,
/* 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))
(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
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);
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);
}
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
if (type == NULL_TREE || type == error_mark_node)
return;
+ /* If TYPE is a typedef type variant, let's generate debug info
+ for the parent typedef which TYPE is a type of. */
if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
{
/* 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;
/* 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
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. */
{
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);
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);
}
'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)
{
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++;
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,
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. */
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 ();
if (fde->dw_fde_switched_sections)
{
- add_ranges_by_labels (fde->dw_fde_hot_section_label,
- fde->dw_fde_hot_section_end_label);
- add_ranges_by_labels (fde->dw_fde_unlikely_section_label,
- fde->dw_fde_unlikely_section_end_label);
+ if (!fde->in_std_section)
+ add_ranges_by_labels (fde->dw_fde_hot_section_label,
+ fde->dw_fde_hot_section_end_label);
+ if (!fde->cold_in_std_section)
+ add_ranges_by_labels (fde->dw_fde_unlikely_section_label,
+ fde->dw_fde_unlikely_section_end_label);
}
- else
+ else if (!fde->in_std_section)
add_ranges_by_labels (fde->dw_fde_begin,
fde->dw_fde_end);
}
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. */
#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 */